#!/usr/bin/env python3
"""
Crypto Sentiment Collector Daemon
Сбор данных + SQLite хранение + Telegram алерты

Запуск: python collector_daemon.py
Cron:   */30 * * * * cd /path/to/project && python collector_daemon.py >> logs/collector.log 2>&1
"""

import os
import json
import sqlite3
import requests
import asyncio
from datetime import datetime, timedelta
from typing import Dict, List, Optional, Any
from dataclasses import dataclass, asdict
import time

# ============== CONFIGURATION ==============

CONFIG = {
    # API Keys
    'coinglass_key': '255ebd9531e64afaadb71993390917f6',
    
    # Telegram
    'telegram_token': '8033073185:AAGCDD0qmYGnUglnEBIFVqAAao1JL0USUSc',
    'telegram_chat_id': '366078798',
    
    # Paths
    'db_path': 'market_data.db',
    'data_dir': 'market_sentiment',
    
    # Symbols
    'symbols': ['BTC', 'ETH'],
    
    # Alert Thresholds
    'thresholds': {
        'ls_ratio_extreme': 1.15,       # L/S > 1.15 = extreme long
        'ls_ratio_short': 0.85,         # L/S < 0.85 = extreme short
        'top_trader_extreme': 2.0,      # Top Trader L/S > 2.0 = extreme
        'hl_divergence': 0.20,          # HL vs CEX divergence
        'liquidation_ratio': 10,        # Long/Short liq ratio
        'funding_extreme': 0.05,        # Funding > 0.05%
        'etf_flow_large': 500,          # $500M+ flow
        'fear_greed_fear': 25,          # F&G < 25
        'fear_greed_greed': 75,         # F&G > 75
        'pc_ratio_low': 0.5,            # P/C < 0.5 = very bullish
        'pc_ratio_high': 1.0,           # P/C > 1.0 = very bearish
    }
}


# ============== DATA CLASSES ==============

@dataclass
class MarketData:
    timestamp: str
    symbol: str
    source: str
    data_type: str
    value: float
    metadata: str = ""


@dataclass 
class Anomaly:
    timestamp: str
    type: str
    symbol: str
    severity: str  # HIGH, MEDIUM, LOW
    message: str
    value: float
    threshold: float
    implication: str


# ============== DATABASE ==============

class Database:
    """SQLite storage for market data"""
    
    def __init__(self, db_path: str):
        self.db_path = db_path
        self.init_db()
    
    def init_db(self):
        """Initialize database tables"""
        conn = sqlite3.connect(self.db_path)
        c = conn.cursor()
        
        # Market data table
        c.execute('''
            CREATE TABLE IF NOT EXISTS market_data (
                id INTEGER PRIMARY KEY AUTOINCREMENT,
                timestamp TEXT,
                symbol TEXT,
                source TEXT,
                data_type TEXT,
                value REAL,
                metadata TEXT,
                created_at TEXT DEFAULT CURRENT_TIMESTAMP
            )
        ''')
        
        # Anomalies table
        c.execute('''
            CREATE TABLE IF NOT EXISTS anomalies (
                id INTEGER PRIMARY KEY AUTOINCREMENT,
                timestamp TEXT,
                type TEXT,
                symbol TEXT,
                severity TEXT,
                message TEXT,
                value REAL,
                threshold REAL,
                implication TEXT,
                alerted INTEGER DEFAULT 0,
                created_at TEXT DEFAULT CURRENT_TIMESTAMP
            )
        ''')
        
        # ETF data table
        c.execute('''
            CREATE TABLE IF NOT EXISTS etf_data (
                id INTEGER PRIMARY KEY AUTOINCREMENT,
                timestamp TEXT,
                ticker TEXT,
                holdings_btc REAL,
                aum_usd REAL,
                flow_24h_btc REAL,
                flow_7d_btc REAL,
                premium_percent REAL,
                created_at TEXT DEFAULT CURRENT_TIMESTAMP
            )
        ''')
        
        # Indexes
        c.execute('CREATE INDEX IF NOT EXISTS idx_market_timestamp ON market_data(timestamp)')
        c.execute('CREATE INDEX IF NOT EXISTS idx_market_symbol ON market_data(symbol)')
        c.execute('CREATE INDEX IF NOT EXISTS idx_anomalies_timestamp ON anomalies(timestamp)')
        
        conn.commit()
        conn.close()
    
    def insert_market_data(self, data: MarketData):
        """Insert market data record"""
        conn = sqlite3.connect(self.db_path)
        c = conn.cursor()
        c.execute('''
            INSERT INTO market_data (timestamp, symbol, source, data_type, value, metadata)
            VALUES (?, ?, ?, ?, ?, ?)
        ''', (data.timestamp, data.symbol, data.source, data.data_type, data.value, data.metadata))
        conn.commit()
        conn.close()
    
    def insert_anomaly(self, anomaly: Anomaly) -> int:
        """Insert anomaly record, return id"""
        conn = sqlite3.connect(self.db_path)
        c = conn.cursor()
        c.execute('''
            INSERT INTO anomalies (timestamp, type, symbol, severity, message, value, threshold, implication)
            VALUES (?, ?, ?, ?, ?, ?, ?, ?)
        ''', (anomaly.timestamp, anomaly.type, anomaly.symbol, anomaly.severity, 
              anomaly.message, anomaly.value, anomaly.threshold, anomaly.implication))
        anomaly_id = c.lastrowid
        conn.commit()
        conn.close()
        return anomaly_id
    
    def insert_etf_data(self, ticker: str, holdings: float, aum: float, 
                        flow_24h: float, flow_7d: float, premium: float):
        """Insert ETF data"""
        conn = sqlite3.connect(self.db_path)
        c = conn.cursor()
        c.execute('''
            INSERT INTO etf_data (timestamp, ticker, holdings_btc, aum_usd, flow_24h_btc, flow_7d_btc, premium_percent)
            VALUES (?, ?, ?, ?, ?, ?, ?)
        ''', (datetime.now().isoformat(), ticker, holdings, aum, flow_24h, flow_7d, premium))
        conn.commit()
        conn.close()
    
    def mark_anomaly_alerted(self, anomaly_id: int):
        """Mark anomaly as alerted"""
        conn = sqlite3.connect(self.db_path)
        c = conn.cursor()
        c.execute('UPDATE anomalies SET alerted = 1 WHERE id = ?', (anomaly_id,))
        conn.commit()
        conn.close()
    
    def get_recent_data(self, symbol: str, data_type: str, hours: int = 24) -> List[dict]:
        """Get recent market data"""
        conn = sqlite3.connect(self.db_path)
        c = conn.cursor()
        cutoff = (datetime.now() - timedelta(hours=hours)).isoformat()
        c.execute('''
            SELECT timestamp, value, metadata FROM market_data
            WHERE symbol = ? AND data_type = ? AND timestamp > ?
            ORDER BY timestamp DESC
        ''', (symbol, data_type, cutoff))
        rows = c.fetchall()
        conn.close()
        return [{'timestamp': r[0], 'value': r[1], 'metadata': r[2]} for r in rows]


# ============== TELEGRAM BOT ==============

class TelegramBot:
    """Telegram alert sender"""
    
    def __init__(self, token: str, chat_id: str):
        self.token = token
        self.chat_id = chat_id
        self.base_url = f"https://api.telegram.org/bot{token}"
    
    def send_message(self, text: str, parse_mode: str = "HTML") -> bool:
        """Send message to Telegram"""
        try:
            url = f"{self.base_url}/sendMessage"
            data = {
                "chat_id": self.chat_id,
                "text": text,
                "parse_mode": parse_mode
            }
            resp = requests.post(url, data=data, timeout=10)
            return resp.status_code == 200
        except Exception as e:
            print(f"❌ Telegram error: {e}")
            return False
    
    def send_anomaly_alert(self, anomaly: Anomaly) -> bool:
        """Send formatted anomaly alert"""
        emoji = "🔴" if anomaly.severity == "HIGH" else "🟡" if anomaly.severity == "MEDIUM" else "🟢"
        
        text = f"""
{emoji} <b>{anomaly.type}</b>

<b>Symbol:</b> {anomaly.symbol}
<b>Severity:</b> {anomaly.severity}
<b>Value:</b> {anomaly.value:.4f}
<b>Threshold:</b> {anomaly.threshold:.4f}

<b>Message:</b>
{anomaly.message}

<b>Implication:</b>
{anomaly.implication}

<i>{anomaly.timestamp}</i>
"""
        return self.send_message(text.strip())
    
    def send_daily_summary(self, summary: dict) -> bool:
        """Send daily summary"""
        text = f"""
📊 <b>Daily Market Summary</b>

<b>BTC:</b> ${summary.get('btc_price', 0):,.0f}
• L/S Ratio: {summary.get('btc_ls', 0):.2f}
• Funding: {summary.get('btc_funding', 0):.4f}%

<b>ETH:</b> ${summary.get('eth_price', 0):,.0f}
• L/S Ratio: {summary.get('eth_ls', 0):.2f}
• Funding: {summary.get('eth_funding', 0):.4f}%

<b>Fear & Greed:</b> {summary.get('fear_greed', 50)}

<b>ETF Flows 24h:</b> {summary.get('etf_flow_24h', 0):+,.0f} BTC

<b>Anomalies Today:</b> {summary.get('anomaly_count', 0)}

<i>{datetime.now().strftime('%Y-%m-%d %H:%M')}</i>
"""
        return self.send_message(text.strip())


# ============== DATA COLLECTORS ==============

class CoinglassV2:
    """Coinglass API V2 (L/S Ratio, Liquidations)"""
    
    BASE_URL = "https://open-api.coinglass.com/public/v2"
    
    def __init__(self, api_key: str):
        self.headers = {
            "accept": "application/json",
            "coinglassSecret": api_key
        }
    
    def _get(self, endpoint: str, params: dict = None) -> dict:
        try:
            url = f"{self.BASE_URL}{endpoint}"
            resp = requests.get(url, headers=self.headers, params=params, timeout=15)
            data = resp.json()
            if data.get('code') == '0':
                return data.get('data', {})
        except Exception as e:
            print(f"  ⚠️ CG V2 error: {e}")
        return {}
    
    def get_long_short_ratio(self, symbol: str) -> dict:
        """Get L/S ratio by exchange (all accounts)"""
        data = self._get("/long_short", {"symbol": symbol, "time_type": "h24"})
        if data and isinstance(data, list) and data:
            return data[0]
        return {}
    
    def get_liquidation_info(self, symbol: str) -> dict:
        """Get liquidation info"""
        return self._get("/liquidation_info", {"symbol": symbol, "time_type": "h24"})


class BinanceTopTrader:
    """Binance Futures Top Trader L/S Ratio (FREE API - no key needed)"""
    
    BASE_URL = "https://fapi.binance.com/futures/data"
    
    def _get(self, endpoint: str, params: dict) -> List[dict]:
        try:
            url = f"{self.BASE_URL}/{endpoint}"
            resp = requests.get(url, params=params, timeout=15)
            data = resp.json()
            if isinstance(data, list):
                return data
        except Exception as e:
            print(f"  ⚠️ Binance error: {e}")
        return []
    
    def get_top_accounts_ratio(self, symbol: str = "BTCUSDT", period: str = "4h") -> dict:
        """Get Top Trader L/S by accounts count (top 20% traders)"""
        data = self._get("topLongShortAccountRatio", {"symbol": symbol, "period": period, "limit": 1})
        if data:
            d = data[-1]
            return {
                'longShortRatio': float(d.get('longShortRatio', 1)),
                'longAccount': float(d.get('longAccount', 0.5)) * 100,
                'shortAccount': float(d.get('shortAccount', 0.5)) * 100,
                'timestamp': d.get('timestamp')
            }
        return {}
    
    def get_top_positions_ratio(self, symbol: str = "BTCUSDT", period: str = "4h") -> dict:
        """Get Top Trader L/S by position size (top 20% by volume)"""
        data = self._get("topLongShortPositionRatio", {"symbol": symbol, "period": period, "limit": 1})
        if data:
            d = data[-1]
            return {
                'longShortRatio': float(d.get('longShortRatio', 1)),
                'longAccount': float(d.get('longAccount', 0.5)) * 100,
                'shortAccount': float(d.get('shortAccount', 0.5)) * 100,
                'timestamp': d.get('timestamp')
            }
        return {}
    
    def get_global_ratio(self, symbol: str = "BTCUSDT", period: str = "4h") -> dict:
        """Get Global L/S by all accounts"""
        data = self._get("globalLongShortAccountRatio", {"symbol": symbol, "period": period, "limit": 1})
        if data:
            d = data[-1]
            return {
                'longShortRatio': float(d.get('longShortRatio', 1)),
                'longAccount': float(d.get('longAccount', 0.5)) * 100,
                'shortAccount': float(d.get('shortAccount', 0.5)) * 100,
                'timestamp': d.get('timestamp')
            }
        return {}


class CoinglassV4:
    """Coinglass API V4 (ETF, Funding, OI)"""
    
    BASE_URL = "https://open-api-v4.coinglass.com/api"
    
    def __init__(self, api_key: str):
        self.headers = {
            "accept": "application/json",
            "CG-API-KEY": api_key
        }
    
    def _get(self, endpoint: str, params: dict = None) -> Any:
        try:
            url = f"{self.BASE_URL}{endpoint}"
            resp = requests.get(url, headers=self.headers, params=params, timeout=15)
            data = resp.json()
            if data.get('code') == '0':
                return data.get('data', {})
        except Exception as e:
            print(f"  ⚠️ CG V4 error: {e}")
        return {}
    
    def get_btc_etf_list(self) -> List[dict]:
        """Get BTC ETF list with flows"""
        data = self._get("/etf/bitcoin/list")
        return data if isinstance(data, list) else []
    
    def get_eth_etf_list(self) -> List[dict]:
        """Get ETH ETF list"""
        data = self._get("/etf/ethereum/list")
        return data if isinstance(data, list) else []
    
    def get_funding_by_exchange(self, symbol: str) -> List[dict]:
        """Get funding rates by exchange"""
        data = self._get("/futures/funding-rate/exchange-list", {"symbol": symbol})
        
        # V4 returns nested structure with stablecoin_margin_list
        if isinstance(data, list) and data:
            # Find the symbol data
            for item in data:
                if item.get('symbol') == symbol:
                    # Return stablecoin margin list (main perps)
                    return item.get('stablecoin_margin_list', [])
        
        return data if isinstance(data, list) else []
    
    def get_oi_by_exchange(self, symbol: str) -> List[dict]:
        """Get OI by exchange"""
        data = self._get("/futures/open-interest/exchange-list", {"symbol": symbol})
        return data if isinstance(data, list) else []


class DeribitCollector:
    """Deribit options data (free API)"""
    
    BASE_URL = "https://www.deribit.com/api/v2/public"
    
    def _get(self, endpoint: str, params: dict = None) -> Any:
        try:
            url = f"{self.BASE_URL}/{endpoint}"
            resp = requests.get(url, params=params, timeout=15)
            data = resp.json()
            if 'result' in data:
                return data['result']
        except Exception as e:
            print(f"  ⚠️ Deribit error: {e}")
        return {}
    
    def get_options_summary(self, currency: str = "BTC") -> dict:
        """Get options summary (P/C ratio, OI)"""
        instruments = self._get("get_book_summary_by_currency", {
            "currency": currency,
            "kind": "option"
        })
        
        if not instruments:
            return {}
        
        calls_oi = 0
        puts_oi = 0
        
        for inst in instruments:
            name = inst.get('instrument_name', '')
            oi = inst.get('open_interest', 0)
            
            if '-C' in name:
                calls_oi += oi
            elif '-P' in name:
                puts_oi += oi
        
        pc_ratio = puts_oi / calls_oi if calls_oi > 0 else 0
        
        return {
            'calls_oi': calls_oi,
            'puts_oi': puts_oi,
            'total_oi': calls_oi + puts_oi,
            'pc_ratio': pc_ratio
        }


class FearGreedCollector:
    """Fear & Greed Index"""
    
    URL = "https://api.alternative.me/fng/?limit=1"
    
    def get_current(self) -> dict:
        try:
            resp = requests.get(self.URL, timeout=10)
            data = resp.json()
            if data.get('data'):
                return {
                    'value': int(data['data'][0]['value']),
                    'classification': data['data'][0]['value_classification']
                }
        except Exception as e:
            print(f"  ⚠️ F&G error: {e}")
        return {'value': 50, 'classification': 'Neutral'}


# ============== ANOMALY DETECTOR ==============

class AnomalyDetector:
    """Detect market anomalies"""
    
    def __init__(self, thresholds: dict):
        self.thresholds = thresholds
    
    def detect_all(self, data: dict) -> List[Anomaly]:
        """Run all anomaly detections"""
        anomalies = []
        ts = datetime.now().isoformat()
        
        # L/S Ratio anomalies
        anomalies.extend(self._check_ls_ratio(data, ts))
        
        # Top Trader anomalies
        anomalies.extend(self._check_top_trader(data, ts))
        
        # HL Divergence
        anomalies.extend(self._check_hl_divergence(data, ts))
        
        # Liquidations
        anomalies.extend(self._check_liquidations(data, ts))
        
        # Fear & Greed
        anomalies.extend(self._check_fear_greed(data, ts))
        
        # ETF Flows
        anomalies.extend(self._check_etf_flows(data, ts))
        
        # Options P/C Ratio
        anomalies.extend(self._check_options(data, ts))
        
        # Cross-reference
        anomalies.extend(self._check_cross_reference(data, ts))
        
        return anomalies
    
    def _check_top_trader(self, data: dict, ts: str) -> List[Anomaly]:
        """Check top trader L/S ratio extremes (Binance data)"""
        anomalies = []
        
        for symbol in ['BTC', 'ETH']:
            top_acc = data.get('top_trader_accounts', {}).get(symbol, {})
            top_pos = data.get('top_trader_positions', {}).get(symbol, {})
            
            # Check accounts ratio (new Binance structure)
            if top_acc and 'longShortRatio' in top_acc:
                ratio = top_acc['longShortRatio']
                long_pct = top_acc.get('longAccount', 50)
                
                if ratio > self.thresholds['top_trader_extreme']:
                    anomalies.append(Anomaly(
                        timestamp=ts,
                        type="TOP_TRADER_EXTREME_LONG",
                        symbol=symbol,
                        severity="HIGH",
                        message=f"{symbol} Binance Top Accounts L/S {ratio:.2f} — {long_pct:.1f}% в лонгах",
                        value=ratio,
                        threshold=self.thresholds['top_trader_extreme'],
                        implication="Топ трейдеры Binance сильно в лонгах — риск коррекции!"
                    ))
                elif ratio < 1 / self.thresholds['top_trader_extreme']:
                    anomalies.append(Anomaly(
                        timestamp=ts,
                        type="TOP_TRADER_EXTREME_SHORT",
                        symbol=symbol,
                        severity="HIGH",
                        message=f"{symbol} Binance Top Accounts L/S {ratio:.2f} — {100-long_pct:.1f}% в шортах",
                        value=ratio,
                        threshold=1/self.thresholds['top_trader_extreme'],
                        implication="Топ трейдеры Binance сильно в шортах — риск short squeeze"
                    ))
            
            # Check positions ratio (new Binance structure)
            if top_pos and 'longShortRatio' in top_pos:
                ratio = top_pos['longShortRatio']
                long_pct = top_pos.get('longAccount', 50)
                
                if ratio > self.thresholds['top_trader_extreme']:
                    anomalies.append(Anomaly(
                        timestamp=ts,
                        type="BINANCE_TOP_POSITIONS_EXTREME",
                        symbol=symbol,
                        severity="HIGH",
                        message=f"{symbol} Binance Top Positions L/S {ratio:.2f} — {long_pct:.1f}% лонги",
                        value=ratio,
                        threshold=self.thresholds['top_trader_extreme'],
                        implication="🚨 Binance киты L/S > 2.0 — это твой сигнал!"
                    ))
        
        return anomalies
    
    def _check_ls_ratio(self, data: dict, ts: str) -> List[Anomaly]:
        anomalies = []
        
        for symbol in ['BTC', 'ETH']:
            ls_data = data.get('ls_ratio', {}).get(symbol, {})
            if not ls_data:
                continue
            
            avg_ls = ls_data.get('longRate', 50) / ls_data.get('shortRate', 50) if ls_data.get('shortRate', 50) > 0 else 1
            
            if avg_ls > self.thresholds['ls_ratio_extreme']:
                anomalies.append(Anomaly(
                    timestamp=ts,
                    type="EXTREME_LONG_BIAS",
                    symbol=symbol,
                    severity="HIGH",
                    message=f"{symbol} L/S Ratio {avg_ls:.2f} — {ls_data.get('longRate', 50):.1f}% в лонгах",
                    value=avg_ls,
                    threshold=self.thresholds['ls_ratio_extreme'],
                    implication="Высокий риск long squeeze при падении"
                ))
            elif avg_ls < self.thresholds['ls_ratio_short']:
                anomalies.append(Anomaly(
                    timestamp=ts,
                    type="EXTREME_SHORT_BIAS",
                    symbol=symbol,
                    severity="HIGH",
                    message=f"{symbol} L/S Ratio {avg_ls:.2f} — {ls_data.get('shortRate', 50):.1f}% в шортах",
                    value=avg_ls,
                    threshold=self.thresholds['ls_ratio_short'],
                    implication="Высокий риск short squeeze при росте"
                ))
        
        return anomalies
    
    def _check_hl_divergence(self, data: dict, ts: str) -> List[Anomaly]:
        anomalies = []
        
        for symbol in ['BTC', 'ETH']:
            ls_data = data.get('ls_ratio', {}).get(symbol, {})
            exchanges = ls_data.get('list', [])
            
            if not exchanges:
                continue
            
            # Find HL and CEX average
            hl_ls = None
            cex_ratios = []
            
            for ex in exchanges:
                name = ex.get('exchangeName', '').lower()
                long_rate = ex.get('longRate', 50)
                short_rate = ex.get('shortRate', 50)
                ratio = long_rate / short_rate if short_rate > 0 else 1
                
                if 'hyperliquid' in name:
                    hl_ls = ratio
                elif name in ['binance', 'bybit', 'okx']:
                    cex_ratios.append(ratio)
            
            if hl_ls and cex_ratios:
                cex_avg = sum(cex_ratios) / len(cex_ratios)
                divergence = abs(hl_ls - cex_avg)
                
                if divergence > self.thresholds['hl_divergence']:
                    direction = "BEARISH" if hl_ls < cex_avg else "BULLISH"
                    anomalies.append(Anomaly(
                        timestamp=ts,
                        type="HL_DIVERGENCE",
                        symbol=symbol,
                        severity="HIGH",
                        message=f"{symbol} HL L/S {hl_ls:.3f} vs CEX avg {cex_avg:.3f} — HL более {direction}",
                        value=divergence,
                        threshold=self.thresholds['hl_divergence'],
                        implication=f"Hyperliquid трейдеры {'шортят' if direction == 'BEARISH' else 'лонгуют'} агрессивнее CEX"
                    ))
        
        return anomalies
    
    def _check_liquidations(self, data: dict, ts: str) -> List[Anomaly]:
        anomalies = []
        
        for symbol in ['BTC', 'ETH']:
            liq_data = data.get('liquidations', {}).get(symbol, {})
            if not liq_data:
                continue
            
            long_liq = liq_data.get('longVolUsd24h', 0)
            short_liq = liq_data.get('shortVolUsd24h', 0)
            
            if short_liq > 0:
                ratio = long_liq / short_liq
                if ratio > self.thresholds['liquidation_ratio']:
                    anomalies.append(Anomaly(
                        timestamp=ts,
                        type="LIQUIDATION_IMBALANCE",
                        symbol=symbol,
                        severity="HIGH",
                        message=f"{symbol} Long liqs ${long_liq/1e6:.1f}M vs Short ${short_liq/1e6:.1f}M — Ratio {ratio:.1f}:1",
                        value=ratio,
                        threshold=self.thresholds['liquidation_ratio'],
                        implication="Лонги массово ликвидируются — давление на цену вниз"
                    ))
                elif ratio < 1 / self.thresholds['liquidation_ratio']:
                    anomalies.append(Anomaly(
                        timestamp=ts,
                        type="LIQUIDATION_IMBALANCE",
                        symbol=symbol,
                        severity="HIGH",
                        message=f"{symbol} Short liqs ${short_liq/1e6:.1f}M vs Long ${long_liq/1e6:.1f}M — Ratio 1:{1/ratio:.1f}",
                        value=1/ratio,
                        threshold=self.thresholds['liquidation_ratio'],
                        implication="Шорты массово ликвидируются — давление на цену вверх"
                    ))
        
        return anomalies
    
    def _check_fear_greed(self, data: dict, ts: str) -> List[Anomaly]:
        anomalies = []
        
        fg = data.get('fear_greed', {})
        value = fg.get('value', 50)
        
        if value <= self.thresholds['fear_greed_fear']:
            anomalies.append(Anomaly(
                timestamp=ts,
                type="EXTREME_FEAR",
                symbol="MARKET",
                severity="MEDIUM",
                message=f"Fear & Greed Index: {value} ({fg.get('classification', 'Fear')})",
                value=value,
                threshold=self.thresholds['fear_greed_fear'],
                implication="Экстремальный страх — возможная точка покупки"
            ))
        elif value >= self.thresholds['fear_greed_greed']:
            anomalies.append(Anomaly(
                timestamp=ts,
                type="EXTREME_GREED",
                symbol="MARKET",
                severity="MEDIUM",
                message=f"Fear & Greed Index: {value} ({fg.get('classification', 'Greed')})",
                value=value,
                threshold=self.thresholds['fear_greed_greed'],
                implication="Экстремальная жадность — возможная точка продажи"
            ))
        
        return anomalies
    
    def _check_etf_flows(self, data: dict, ts: str) -> List[Anomaly]:
        anomalies = []
        
        etf_data = data.get('etf', {})
        total_flow_24h = 0
        
        for etf in etf_data.get('btc', []):
            details = etf.get('asset_details', {})
            flow = details.get('change_quantity_24h', 0) or 0
            total_flow_24h += flow
        
        if abs(total_flow_24h) > self.thresholds['etf_flow_large']:
            direction = "INFLOW" if total_flow_24h > 0 else "OUTFLOW"
            anomalies.append(Anomaly(
                timestamp=ts,
                type=f"ETF_{direction}",
                symbol="BTC",
                severity="MEDIUM",
                message=f"BTC ETF {direction}: {total_flow_24h:+,.0f} BTC за 24h",
                value=abs(total_flow_24h),
                threshold=self.thresholds['etf_flow_large'],
                implication=f"Институционалы {'заходят' if direction == 'INFLOW' else 'выходят'}"
            ))
        
        return anomalies
    
    def _check_options(self, data: dict, ts: str) -> List[Anomaly]:
        anomalies = []
        
        for symbol in ['BTC', 'ETH']:
            opts = data.get('options', {}).get(symbol, {})
            pc_ratio = opts.get('pc_ratio', 0.7)
            
            if pc_ratio < self.thresholds['pc_ratio_low']:
                anomalies.append(Anomaly(
                    timestamp=ts,
                    type="LOW_PUT_CALL",
                    symbol=symbol,
                    severity="MEDIUM",
                    message=f"{symbol} Put/Call Ratio: {pc_ratio:.3f} — мало хеджирования",
                    value=pc_ratio,
                    threshold=self.thresholds['pc_ratio_low'],
                    implication="Опционщики очень бычьи, нет защиты от падения"
                ))
            elif pc_ratio > self.thresholds['pc_ratio_high']:
                anomalies.append(Anomaly(
                    timestamp=ts,
                    type="HIGH_PUT_CALL",
                    symbol=symbol,
                    severity="MEDIUM",
                    message=f"{symbol} Put/Call Ratio: {pc_ratio:.3f} — много хеджирования",
                    value=pc_ratio,
                    threshold=self.thresholds['pc_ratio_high'],
                    implication="Опционщики хеджируются или ставят на падение"
                ))
        
        return anomalies
    
    def _check_cross_reference(self, data: dict, ts: str) -> List[Anomaly]:
        """Cross-reference perps + options + taker"""
        anomalies = []
        
        for symbol in ['BTC', 'ETH']:
            ls_data = data.get('ls_ratio', {}).get(symbol, {})
            opts = data.get('options', {}).get(symbol, {})
            taker = data.get('taker_flow', {}).get(symbol, {})
            
            if not ls_data:
                continue
            
            ls_ratio = ls_data.get('longRate', 50) / ls_data.get('shortRate', 50) if ls_data.get('shortRate', 50) > 0 else 1
            pc_ratio = opts.get('pc_ratio', 0.7) if opts else 0.7
            taker_ratio = taker.get('ratio', 1) if taker else 1
            
            # Crowded bullish without hedge
            if ls_ratio > 1.1 and pc_ratio < 0.6:
                anomalies.append(Anomaly(
                    timestamp=ts,
                    type="CROWDED_UNHEDGED",
                    symbol=symbol,
                    severity="HIGH",
                    message=f"{symbol} L/S {ls_ratio:.2f} + P/C {pc_ratio:.3f} — все в лонгах без хеджа",
                    value=ls_ratio,
                    threshold=1.1,
                    implication="Максимальный риск! При падении некому покупать"
                ))
            
            # Smart money exit: high L/S but taker selling
            if ls_ratio > 1.05 and taker_ratio < 0.92:
                anomalies.append(Anomaly(
                    timestamp=ts,
                    type="SMART_MONEY_EXIT",
                    symbol=symbol,
                    severity="HIGH",
                    message=f"{symbol} L/S {ls_ratio:.2f} но Taker ПРОДАЮТ ({taker_ratio:.3f})",
                    value=taker_ratio,
                    threshold=0.92,
                    implication="Крупные игроки выходят, retail держит лонги — ОПАСНО"
                ))
            
            # Smart money accumulation: low L/S but taker buying
            if ls_ratio < 0.95 and taker_ratio > 1.08:
                anomalies.append(Anomaly(
                    timestamp=ts,
                    type="SMART_MONEY_ACCUMULATION",
                    symbol=symbol,
                    severity="MEDIUM",
                    message=f"{symbol} L/S {ls_ratio:.2f} но Taker ПОКУПАЮТ ({taker_ratio:.3f})",
                    value=taker_ratio,
                    threshold=1.08,
                    implication="Крупные игроки набирают позицию — возможен рост"
                ))
        
        return anomalies


# ============== MAIN COLLECTOR ==============

class MarketCollector:
    """Main data collector"""
    
    def __init__(self):
        self.db = Database(CONFIG['db_path'])
        self.telegram = TelegramBot(CONFIG['telegram_token'], CONFIG['telegram_chat_id'])
        self.detector = AnomalyDetector(CONFIG['thresholds'])
        
        # Collectors
        self.cg_v2 = CoinglassV2(CONFIG['coinglass_key'])
        self.cg_v4 = CoinglassV4(CONFIG['coinglass_key'])
        self.binance = BinanceTopTrader()
        self.deribit = DeribitCollector()
        self.fear_greed = FearGreedCollector()
    
    def collect_all(self) -> dict:
        """Collect all market data"""
        print(f"\n{'='*60}")
        print(f"📊 COLLECTING MARKET DATA - {datetime.now().strftime('%Y-%m-%d %H:%M')}")
        print(f"{'='*60}")
        
        data = {
            'timestamp': datetime.now().isoformat(),
            'ls_ratio': {},
            'ls_by_exchange': {},
            'top_trader_accounts': {},
            'top_trader_positions': {},
            'liquidations': {},
            'etf': {'btc': [], 'eth': []},
            'funding': {},
            'funding_by_exchange': {},
            'oi': {},
            'oi_by_exchange': {},
            'options': {},
            'fear_greed': {},
            'taker_flow': {},
            'smart_money_signals': {}
        }
        
        # ============== L/S RATIO ==============
        print("\n📈 L/S Ratio...")
        for symbol in CONFIG['symbols']:
            ls = self.cg_v2.get_long_short_ratio(symbol)
            if ls:
                data['ls_ratio'][symbol] = ls
                data['ls_by_exchange'][symbol] = ls.get('list', [])
                
                print(f"\n   {symbol}: Long {ls.get('longRate', 0):.1f}% / Short {ls.get('shortRate', 0):.1f}%")
                
                # Детали по биржам
                exchanges = ls.get('list', [])
                hl_ls = None
                cex_ratios = []
                taker_buy = 0
                taker_sell = 0
                
                print(f"   {'Exchange':<15} {'Long%':>8} {'Short%':>8} {'L/S':>8}")
                print(f"   {'-'*43}")
                
                for ex in exchanges[:10]:  # Top 10
                    name = ex.get('exchangeName', 'Unknown')
                    long_r = ex.get('longRate', 50)
                    short_r = ex.get('shortRate', 50)
                    ratio = long_r / short_r if short_r > 0 else 1
                    
                    # Taker data
                    buy_num = ex.get('buyTurnoverNumber', 0)
                    sell_num = ex.get('sellTurnoverNumber', 0)
                    taker_buy += buy_num
                    taker_sell += sell_num
                    
                    flag = "🐻" if ratio < 0.9 else "🐂" if ratio > 1.1 else ""
                    print(f"   {name:<15} {long_r:>7.1f}% {short_r:>7.1f}% {ratio:>7.3f} {flag}")
                    
                    if 'hyperliquid' in name.lower():
                        hl_ls = ratio
                    elif name.lower() in ['binance', 'bybit', 'okx']:
                        cex_ratios.append(ratio)
                
                # Taker Buy/Sell Summary
                taker_ratio = taker_buy / taker_sell if taker_sell > 0 else 1
                data['taker_flow'][symbol] = {
                    'buy_count': taker_buy,
                    'sell_count': taker_sell,
                    'ratio': taker_ratio
                }
                
                taker_signal = "🟢 BUYING" if taker_ratio > 1.05 else "🔴 SELLING" if taker_ratio < 0.95 else "⚪ NEUTRAL"
                print(f"\n   Taker Flow: Buy {taker_buy:,} / Sell {taker_sell:,} = {taker_ratio:.3f} {taker_signal}")
                
                # HL Divergence
                if hl_ls and cex_ratios:
                    cex_avg = sum(cex_ratios) / len(cex_ratios)
                    divergence = hl_ls - cex_avg
                    div_signal = "🐻 HL BEARISH" if divergence < -0.1 else "🐂 HL BULLISH" if divergence > 0.1 else ""
                    print(f"   HL vs CEX: {hl_ls:.3f} vs {cex_avg:.3f} (div: {divergence:+.3f}) {div_signal}")
                
                # Smart Money Signal
                avg_ls = ls.get('longRate', 50) / ls.get('shortRate', 50) if ls.get('shortRate', 50) > 0 else 1
                smart_signal = "NEUTRAL"
                if avg_ls > 1.1 and taker_ratio < 0.95:
                    smart_signal = "🔴 SMART MONEY EXITING — Лонги доминируют, но крупные ПРОДАЮТ"
                elif avg_ls < 0.9 and taker_ratio > 1.05:
                    smart_signal = "🟢 SMART MONEY ACCUMULATING — Шорты доминируют, но крупные ПОКУПАЮТ"
                elif avg_ls > 1.15:
                    smart_signal = "⚠️ CROWDED LONG — Риск squeeze"
                elif avg_ls < 0.85:
                    smart_signal = "⚠️ CROWDED SHORT — Риск squeeze"
                
                data['smart_money_signals'][symbol] = smart_signal
                if smart_signal != "NEUTRAL":
                    print(f"\n   💡 {smart_signal}")
                
                # Save to DB
                self.db.insert_market_data(MarketData(
                    timestamp=data['timestamp'],
                    symbol=symbol,
                    source='coinglass',
                    data_type='ls_ratio',
                    value=avg_ls,
                    metadata=json.dumps({'ls': ls, 'taker_ratio': taker_ratio})
                ))
        
        # ============== TOP TRADER L/S (Binance) ==============
        print(f"\n{'='*60}")
        print("🐋 Top Trader Long/Short Ratio (Binance 4h)...")
        
        symbol_map = {'BTC': 'BTCUSDT', 'ETH': 'ETHUSDT'}
        
        for symbol in CONFIG['symbols']:
            binance_symbol = symbol_map.get(symbol, f"{symbol}USDT")
            
            # Get all three metrics
            top_acc = self.binance.get_top_accounts_ratio(binance_symbol, "4h")
            top_pos = self.binance.get_top_positions_ratio(binance_symbol, "4h")
            global_acc = self.binance.get_global_ratio(binance_symbol, "4h")
            
            # Store in data
            data['top_trader_accounts'][symbol] = top_acc
            data['top_trader_positions'][symbol] = top_pos
            data['binance_global_ls'] = data.get('binance_global_ls', {})
            data['binance_global_ls'][symbol] = global_acc
            
            print(f"\n   {symbol}:")
            print(f"   {'Metric':<25} {'L/S Ratio':>12} {'Long%':>10} {'Short%':>10}")
            print(f"   {'-'*60}")
            
            if top_acc:
                ratio = top_acc['longShortRatio']
                flag = "🐂🐂" if ratio > 2.0 else "🐂" if ratio > 1.5 else "🐻" if ratio < 0.67 else ""
                print(f"   {'Top Trader Accounts':<25} {ratio:>10.2f} {flag} {top_acc['longAccount']:>9.1f}% {top_acc['shortAccount']:>9.1f}%")
            
            if top_pos:
                ratio = top_pos['longShortRatio']
                flag = "🐂🐂" if ratio > 2.0 else "🐂" if ratio > 1.5 else "🐻" if ratio < 0.67 else ""
                print(f"   {'Top Trader Positions':<25} {ratio:>10.2f} {flag} {top_pos['longAccount']:>9.1f}% {top_pos['shortAccount']:>9.1f}%")
            
            if global_acc:
                ratio = global_acc['longShortRatio']
                flag = "🐂🐂" if ratio > 2.0 else "🐂" if ratio > 1.5 else "🐻" if ratio < 0.67 else ""
                print(f"   {'Global Accounts':<25} {ratio:>10.2f} {flag} {global_acc['longAccount']:>9.1f}% {global_acc['shortAccount']:>9.1f}%")
            
            # Alerts
            if top_pos and top_pos['longShortRatio'] > 2.0:
                print(f"\n   🚨 EXTREME LONG BIAS — Top Traders L/S > 2.0!")
            elif top_pos and top_pos['longShortRatio'] > 1.5:
                print(f"\n   ⚠️ HIGH LONG BIAS — Top Traders в лонгах")
            elif top_pos and top_pos['longShortRatio'] < 0.5:
                print(f"\n   ⚠️ HIGH SHORT BIAS — Top Traders в шортах")
        
        # ============== LIQUIDATIONS ==============
        print(f"\n{'='*60}")
        print("💥 Liquidations...")
        for symbol in CONFIG['symbols']:
            liq = self.cg_v2.get_liquidation_info(symbol)
            if liq:
                data['liquidations'][symbol] = liq
                
                long_1h = liq.get('longVolUsd1h', 0)
                short_1h = liq.get('shortVolUsd1h', 0)
                long_4h = liq.get('longVolUsd4h', 0)
                short_4h = liq.get('shortVolUsd4h', 0)
                long_24h = liq.get('longVolUsd24h', 0)
                short_24h = liq.get('shortVolUsd24h', 0)
                
                ratio_24h = long_24h / short_24h if short_24h > 0 else 0
                
                print(f"\n   {symbol}:")
                print(f"   {'Period':<10} {'Long Liqs':>15} {'Short Liqs':>15} {'Ratio':>10}")
                print(f"   {'-'*52}")
                print(f"   {'1h':<10} ${long_1h/1e6:>13.2f}M ${short_1h/1e6:>13.2f}M {long_1h/(short_1h+1):.1f}:1")
                print(f"   {'4h':<10} ${long_4h/1e6:>13.2f}M ${short_4h/1e6:>13.2f}M {long_4h/(short_4h+1):.1f}:1")
                print(f"   {'24h':<10} ${long_24h/1e6:>13.2f}M ${short_24h/1e6:>13.2f}M {ratio_24h:.1f}:1")
                
                if ratio_24h > 5:
                    print(f"   ⚠️ ЛОНГИ ГОРЯТ — давление на цену ВНИЗ")
                elif ratio_24h < 0.2:
                    print(f"   ⚠️ ШОРТЫ ГОРЯТ — давление на цену ВВЕРХ")
        
        # ============== ETF ==============
        print(f"\n{'='*60}")
        print("📊 ETF Data...")
        btc_etfs = self.cg_v4.get_btc_etf_list()
        if btc_etfs:
            data['etf']['btc'] = btc_etfs
            
            print(f"\n   {'Ticker':<8} {'Holdings BTC':>15} {'24h Flow':>12} {'7d Flow':>12} {'Premium':>10}")
            print(f"   {'-'*62}")
            
            total_holdings = 0
            total_flow_24h = 0
            total_flow_7d = 0
            
            for etf in btc_etfs:
                ticker = etf.get('ticker', '')
                fund_type = etf.get('fund_type', '')
                if fund_type != 'Spot':  # Только спотовые ETF
                    continue
                    
                details = etf.get('asset_details', {})
                holdings = details.get('holding_quantity', 0) or 0
                flow_24h = details.get('change_quantity_24h', 0) or 0
                flow_7d = details.get('change_quantity_7d', 0) or 0
                premium = details.get('premium_discount_percent', 0) or 0
                
                total_holdings += holdings
                total_flow_24h += flow_24h
                total_flow_7d += flow_7d
                
                flow_emoji = "🟢" if flow_24h > 0 else "🔴" if flow_24h < 0 else "⚪"
                print(f"   {ticker:<8} {holdings:>14,.0f} {flow_emoji}{flow_24h:>+10,.0f} {flow_7d:>+11,.0f} {premium:>+9.2f}%")
                
                # Save to DB
                self.db.insert_etf_data(
                    ticker=ticker,
                    holdings=holdings,
                    aum=float(etf.get('aum_usd', 0) or 0),
                    flow_24h=flow_24h,
                    flow_7d=flow_7d,
                    premium=premium
                )
            
            print(f"   {'-'*62}")
            flow_emoji = "🟢" if total_flow_24h > 0 else "🔴" if total_flow_24h < 0 else "⚪"
            print(f"   {'TOTAL':<8} {total_holdings:>14,.0f} {flow_emoji}{total_flow_24h:>+10,.0f} {total_flow_7d:>+11,.0f}")
            
            if total_flow_24h < -1000:
                print(f"\n   ⚠️ ИНСТИТУЦИОНАЛЫ ВЫХОДЯТ — отток {abs(total_flow_24h):,.0f} BTC за 24h")
            elif total_flow_24h > 1000:
                print(f"\n   💚 ИНСТИТУЦИОНАЛЫ ЗАХОДЯТ — приток {total_flow_24h:,.0f} BTC за 24h")
        
        eth_etfs = self.cg_v4.get_eth_etf_list()
        if eth_etfs:
            data['etf']['eth'] = eth_etfs
            
            print(f"\n   ETH ETF:")
            print(f"   {'Ticker':<8} {'Holdings ETH':>15} {'24h Flow':>12} {'7d Flow':>12}")
            print(f"   {'-'*52}")
            
            for etf in eth_etfs[:5]:
                ticker = etf.get('ticker', '')
                fund_type = etf.get('fund_type', '')
                if fund_type != 'Spot':
                    continue
                details = etf.get('asset_details', {})
                holdings = details.get('holding_quantity', 0) or 0
                flow_24h = details.get('change_quantity_24h', 0) or 0
                flow_7d = details.get('change_quantity_7d', 0) or 0
                
                flow_emoji = "🟢" if flow_24h > 0 else "🔴" if flow_24h < 0 else "⚪"
                print(f"   {ticker:<8} {holdings:>14,.0f} {flow_emoji}{flow_24h:>+10,.0f} {flow_7d:>+11,.0f}")
        else:
            print(f"\n   ETH ETF: No data available")
        
        # ============== FUNDING ==============
        print(f"\n{'='*60}")
        print("💰 Funding Rates...")
        for symbol in CONFIG['symbols']:
            funding = self.cg_v4.get_funding_by_exchange(symbol)
            if funding:
                data['funding'][symbol] = funding
                data['funding_by_exchange'][symbol] = funding
                
                print(f"\n   {symbol}:")
                print(f"   {'Exchange':<15} {'Rate':>12} {'Interval':>10} {'Annual':>12}")
                print(f"   {'-'*52}")
                
                rates_8h = []  # Only 8h rates for comparison
                for ex in funding[:10]:
                    name = ex.get('exchange', 'Unknown')
                    rate = ex.get('funding_rate', 0) or 0
                    interval = ex.get('funding_rate_interval', 8)  # hours
                    
                    # Convert to 8h equivalent for comparison
                    rate_8h = rate * (8 / interval) if interval > 0 else rate
                    
                    # Annualized (assuming 8h intervals = 3x per day)
                    annual = rate_8h * 3 * 365
                    
                    rates_8h.append(rate_8h)
                    
                    rate_emoji = "🔴" if rate_8h > 0.03 else "🟢" if rate_8h < -0.01 else ""
                    print(f"   {name:<15} {rate:>+11.4f}% {interval:>9}h {annual:>+11.1f}% {rate_emoji}")
                
                avg_rate = sum(rates_8h) / len(rates_8h) if rates_8h else 0
                print(f"   {'-'*52}")
                print(f"   {'Average (8h eq)':<15} {avg_rate:>+11.4f}%")
                
                if avg_rate > 0.03:
                    print(f"   ⚠️ HIGH FUNDING — лонги платят много, перегрев")
                elif avg_rate < -0.01:
                    print(f"   💡 NEGATIVE FUNDING — шорты платят, редкость")
        
        # ============== OPEN INTEREST ==============
        print(f"\n{'='*60}")
        print("📊 Open Interest...")
        for symbol in CONFIG['symbols']:
            oi = self.cg_v4.get_oi_by_exchange(symbol)
            if oi:
                data['oi'][symbol] = oi
                data['oi_by_exchange'][symbol] = oi
                
                print(f"\n   {symbol}:")
                print(f"   {'Exchange':<15} {'OI (USD)':>18} {'24h Change':>12}")
                print(f"   {'-'*48}")
                
                total_oi = 0
                for ex in oi[:8]:
                    # V4 uses 'exchange' not 'exchangeName'
                    name = ex.get('exchange', ex.get('exchangeName', 'Unknown'))
                    # V4 uses 'open_interest_usd' not 'openInterest'
                    oi_usd = ex.get('open_interest_usd', ex.get('openInterest', 0)) or 0
                    # V4 uses 'open_interest_change_percent_24h'
                    change_24h = ex.get('open_interest_change_percent_24h', ex.get('h24Change', ex.get('oichangePercent', 0))) or 0
                    total_oi += oi_usd
                    
                    change_emoji = "🟢" if change_24h > 3 else "🔴" if change_24h < -3 else ""
                    print(f"   {name:<15} ${oi_usd/1e9:>16.2f}B {change_24h:>+10.1f}% {change_emoji}")
                
                print(f"   {'-'*48}")
                print(f"   {'TOTAL':<15} ${total_oi/1e9:>16.2f}B")
        
        # ============== OPTIONS ==============
        print(f"\n{'='*60}")
        print("📉 Options Data (Deribit)...")
        for symbol in CONFIG['symbols']:
            opts = self.deribit.get_options_summary(symbol)
            if opts:
                data['options'][symbol] = opts
                
                pc = opts.get('pc_ratio', 0)
                calls = opts.get('calls_oi', 0)
                puts = opts.get('puts_oi', 0)
                total = opts.get('total_oi', 0)
                
                pc_signal = "🐻 BEARISH" if pc > 0.9 else "🐂 BULLISH" if pc < 0.5 else "NEUTRAL"
                
                print(f"\n   {symbol}:")
                print(f"   Put/Call Ratio: {pc:.3f} {pc_signal}")
                print(f"   Calls OI: {calls:>15,.0f}")
                print(f"   Puts OI:  {puts:>15,.0f}")
                print(f"   Total OI: {total:>15,.0f}")
                
                if pc < 0.5:
                    print(f"   ⚠️ ОЧЕНЬ МАЛО ХЕДЖИРОВАНИЯ — риск при падении")
        
        # ============== FEAR & GREED ==============
        print(f"\n{'='*60}")
        print("🎭 Fear & Greed Index...")
        fg = self.fear_greed.get_current()
        data['fear_greed'] = fg
        
        value = fg.get('value', 50)
        classification = fg.get('classification', 'Neutral')
        
        if value <= 25:
            emoji = "😱"
            signal = "EXTREME FEAR — возможная точка покупки"
        elif value <= 40:
            emoji = "😰"
            signal = "FEAR"
        elif value <= 60:
            emoji = "😐"
            signal = "NEUTRAL"
        elif value <= 75:
            emoji = "😊"
            signal = "GREED"
        else:
            emoji = "🤑"
            signal = "EXTREME GREED — возможная точка продажи"
        
        print(f"\n   {emoji} Value: {value} ({classification})")
        print(f"   Signal: {signal}")
        
        # ============== SUMMARY ==============
        print(f"\n{'='*60}")
        print("📋 SUMMARY")
        print(f"{'='*60}")
        
        for symbol in CONFIG['symbols']:
            ls = data['ls_ratio'].get(symbol, {})
            ls_val = ls.get('longRate', 50) / ls.get('shortRate', 50) if ls.get('shortRate', 50) > 0 else 1
            taker = data['taker_flow'].get(symbol, {}).get('ratio', 1)
            opts = data['options'].get(symbol, {})
            pc = opts.get('pc_ratio', 0.7)
            smart = data['smart_money_signals'].get(symbol, 'NEUTRAL')
            
            print(f"\n   {symbol}:")
            print(f"   • L/S Ratio: {ls_val:.3f}")
            print(f"   • Taker Ratio: {taker:.3f}")
            print(f"   • Put/Call: {pc:.3f}")
            print(f"   • Signal: {smart}")
        
        return data
    
    def detect_and_alert(self, data: dict):
        """Detect anomalies and send alerts"""
        print(f"\n{'='*60}")
        print("🔍 DETECTING ANOMALIES")
        print(f"{'='*60}")
        
        anomalies = self.detector.detect_all(data)
        
        if not anomalies:
            print("   ✅ No anomalies detected")
            return
        
        print(f"   ⚠️ Found {len(anomalies)} anomalies:")
        
        for anomaly in anomalies:
            # Save to DB
            anomaly_id = self.db.insert_anomaly(anomaly)
            
            emoji = "🔴" if anomaly.severity == "HIGH" else "🟡" if anomaly.severity == "MEDIUM" else "🟢"
            print(f"   {emoji} [{anomaly.type}] {anomaly.symbol}: {anomaly.message}")
            
            # Send HIGH severity alerts immediately
            if anomaly.severity == "HIGH":
                if self.telegram.send_anomaly_alert(anomaly):
                    self.db.mark_anomaly_alerted(anomaly_id)
                    print(f"      → Telegram alert sent")
                time.sleep(1)  # Rate limit
    
    def run(self):
        """Main run loop"""
        try:
            # Collect data
            data = self.collect_all()
            
            # Save raw data to file
            os.makedirs(CONFIG['data_dir'], exist_ok=True)
            filename = f"{CONFIG['data_dir']}/sentiment_{datetime.now().strftime('%Y%m%d_%H%M%S')}.json"
            with open(filename, 'w') as f:
                json.dump(data, f, indent=2, default=str)
            print(f"\n📄 Data saved to: {filename}")
            
            # Detect anomalies and alert
            self.detect_and_alert(data)
            
            print(f"\n{'='*60}")
            print("✅ COLLECTION COMPLETE")
            print(f"{'='*60}\n")
            
        except Exception as e:
            print(f"\n❌ ERROR: {e}")
            self.telegram.send_message(f"❌ Collector Error:\n{str(e)}")


# ============== MAIN ==============

if __name__ == "__main__":
    import argparse
    
    parser = argparse.ArgumentParser(description='Crypto Sentiment Collector')
    parser.add_argument('--once', action='store_true', help='Run once and exit')
    parser.add_argument('--interval', type=int, default=3600, help='Interval in seconds (default: 3600 = 1 hour)')
    args = parser.parse_args()
    
    if args.once:
        # Single run
        collector = MarketCollector()
        collector.run()
    else:
        # Continuous loop
        print(f"""
╔══════════════════════════════════════════════════════════╗
║       CRYPTO SENTIMENT COLLECTOR - DAEMON MODE           ║
║                                                          ║
║   Interval: {args.interval//60} minutes                                    ║
║   Press Ctrl+C to stop                                   ║
╚══════════════════════════════════════════════════════════╝
        """)
        
        while True:
            try:
                collector = MarketCollector()
                collector.run()
            except Exception as e:
                print(f"\n❌ ERROR in collection cycle: {e}")
                # Try to send error notification
                try:
                    from datetime import datetime as dt
                    TelegramBot(CONFIG['telegram_token'], CONFIG['telegram_chat_id']).send_message(
                        f"❌ Collector Error at {dt.now().strftime('%H:%M')}:\n{str(e)[:200]}"
                    )
                except:
                    pass
            
            # Wait for next cycle
            next_run = datetime.now() + timedelta(seconds=args.interval)
            print(f"\n⏰ Next collection at {next_run.strftime('%H:%M:%S')} ({args.interval//60} min)")
            print(f"{'─'*60}\n")
            
            try:
                time.sleep(args.interval)
            except KeyboardInterrupt:
                print("\n\n👋 Stopping collector...")
                break



















