Skill: georges91560/crypto-sniper-oracle (version 3.3.0)

--- name: crypto-sniper-oracle description: Institutional-grade quantitative market oracle with Order Book Imbalance (OBI), VWAP analysis, automated reports, and Telegram alerts. version: 3.3.0 metadata: openclaw: emoji: "🎯" requires: bins: ["python3"] env: [] network_behavior: makes_requests: true endpoints_allowed: - "https://api.binance.com/api/v3/*" - "https://api.telegram.org/bot*" optional_credentials: ["TELEGRAM_BOT_TOKEN", "TELEGRAM_CHAT_ID"] security_level: "L1 - Read-Only Public Data (L2 with Telegram)" author: "Georges Andronescu (Wesley Armando)" license: "MIT" homepage: "https://github.com/georges91560/crypto-sniper-oracle" repository: "https://github.com/georges91560/crypto-sniper-oracle" --- # Crypto Sniper Oracle — Quantitative Market Intelligence + Reporting ## ⚠️ SCOPE & CAPABILITIES **Core Function:** Fetch public market data and generate quantitative analysis. **What it does:** - ✅ Fetches public ticker data from Binance API - ✅ Fetches public order book data from Binance API - ✅ Calculates Order Book Imbalance (OBI) - ✅ Calculates VWAP divergence - ✅ Scores liquidity quality (spread in bps) - ✅ Generates formatted analysis reports - ✅ **[OPTIONAL]** Sends reports via Telegram - ✅ **[OPTIONAL]** Scheduled cron jobs for automated reports **What it does NOT do:** - ❌ Place orders or execute trades - ❌ Transfer funds - ❌ Access private exchange data - ❌ Read agent memory (beyond its own logs) - ❌ Intercept or block other skills --- ## 🔧 Configuration Options ### **Mode 1: Analysis Only (Default)** **No Telegram, manual invocation:** ```bash # Just fetch data and analyze python3 crypto_oracle.py --symbol BTCUSDT ``` **Use case:** Manual analysis on demand. --- ### **Mode 2: Telegram Reports (Optional)** **Enable Telegram alerts and reports:** **Required environment variables:** ```bash export TELEGRAM_BOT_TOKEN="your_bot_token_here" export TELEGRAM_CHAT_ID="your_chat_id_here" ``` **Configuration:** ```json { "skills": { "crypto-sniper-oracle": { "enabled": true, "config": { "telegram_enabled": true } } } } ``` **Use case:** Automated reports sent to Telegram. --- ### **Mode 3: Cron Jobs + Telegram (Automated)** **Scheduled market reports:** **Example cron jobs:** ```bash # Daily report at 9am UTC 0 9 * * * /workspace/skills/crypto-sniper-oracle/reporter.py --mode daily # Hourly anomaly check 0 * * * * /workspace/skills/crypto-sniper-oracle/reporter.py --mode hourly # Price alerts every 15min */15 * * * * /workspace/skills/crypto-sniper-oracle/reporter.py --mode alerts ``` **Use case:** Fully automated market monitoring. --- ## 📊 Report Templates ### **1. Daily Market Report** **Trigger:** Cron (9am daily) or manual command **Content:** ```markdown 📊 CRYPTO MARKET DAILY REPORT {date} | Powered by Wesley ━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 🎯 MARKET OVERVIEW (10 pairs analyzed) 🟢 BULLISH SETUPS (OBI > +0.15) • BTCUSDT: OBI +0.18, Spread 2.1 bps Price vs VWAP: +0.5% (above average) Signal: Strong buying pressure • ETHUSDT: OBI +0.12, Spread 3.5 bps Price vs VWAP: +0.3% Signal: Moderate bullish 🔴 BEARISH SETUPS (OBI < -0.15) • SOLUSDT: OBI -0.16, Spread 8.2 bps Price vs VWAP: -0.8% Signal: Selling pressure 💰 LIQUIDITY QUALITY Excellent (< 5 bps): 5 pairs Good (5-10 bps): 3 pairs Poor (> 30 bps): 2 pairs 📈 TOP MOVERS (24h) +12.3% SOLUSDT (volatility: HIGH) +8.1% ETHUSDT (volatility: MODERATE) -5.2% BNBUSDT (volatility: MODERATE) 🎯 TRADING OPPORTUNITIES → BTC: Bullish setup confirmed (OBI +0.18) → ETH: Moderate strength, watch for breakout → SOL: Avoid - selling pressure + poor liquidity ━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Generated: 2026-02-27 09:00:00 UTC Next report: 2026-02-28 09:00:00 UTC ``` --- ### **2. Anomaly Alert** **Trigger:** OBI spike, spread explosion, or volume surge **Content:** ```markdown 🚨 MARKET ANOMALY DETECTED Time: 15:23:45 UTC Asset: BTCUSDT 📊 Anomaly Type: OBI SPIKE • Previous OBI: +0.05 • Current OBI: +0.22 • Change: +340% in 15 minutes 💰 Liquidity: EXCELLENT (2.3 bps) 📈 Price vs VWAP: +0.6% 💡 Implication: Strong buying pressure surge detected. Potential upward price movement imminent. 🎯 Suggested Action: Consider LONG entry if other signals align. Monitor closely for next 30 minutes. [View Full Analysis] ``` --- ### **3. Hourly Summary** **Trigger:** Cron (every hour) **Content:** ```markdown ⚡ HOURLY MARKET CHECK {timestamp} 🔍 Scanned: 10 pairs 🟢 Bullish: 3 🔴 Bearish: 2 ⚪ Neutral: 5 📊 Notable Changes: • BTC OBI: +0.05 → +0.12 (↑) • ETH Spread: 3.2 → 5.8 bps (↑) ⚠️ Alerts: None Next check: {next_hour} ``` --- ## 🔐 File Access (Expanded) **READ:** - `/workspace/skills/crypto-sniper-oracle/crypto_oracle.py` (data fetcher) - `/workspace/skills/crypto-sniper-oracle/reporter.py` (report generator) - `/workspace/skills/crypto-sniper-oracle/templates/*.md` (report templates) **WRITE:** - `/workspace/.oracle_cache.json` (45s cache) - `/workspace/MARKET_ANALYSIS.md` (analysis reports) - `/workspace/TRADING_LOGS.md` (audit trail) - `/workspace/reports/daily_{date}.md` (archived reports) - `/workspace/reports/alerts_{date}.log` (alert history) --- ## 🌐 Network Access (Expanded) **Always allowed:** - ✅ `https://api.binance.com/api/v3/*` (public market data) **Conditionally allowed (if Telegram enabled):** - ✅ `https://api.telegram.org/bot{token}/*` (send messages only) **Never allowed:** - ❌ Binance private endpoints - ❌ Order placement endpoints - ❌ Withdrawal endpoints --- ## 📋 Cron Job Specifications ### **Daily Report** ```bash # Schedule: 9am UTC daily 0 9 * * * /workspace/skills/crypto-sniper-oracle/reporter.py --mode daily --symbols BTCUSDT,ETHUSDT,SOLUSDT,BNBUSDT,ADAUSDT # What it does: 1. Fetch data for all symbols 2. Calculate OBI, VWAP, spread for each 3. Aggregate into daily report 4. Send via Telegram (if enabled) 5. Archive to /workspace/reports/daily_{date}.md ``` --- ### **Hourly Check** ```bash # Schedule: Every hour 0 * * * * /workspace/skills/crypto-sniper-oracle/reporter.py --mode hourly --symbols BTCUSDT,ETHUSDT # What it does: 1. Quick scan of key pairs 2. Compare vs previous hour 3. Detect significant changes 4. Alert if anomaly detected ``` --- ### **Price Alerts** ```bash # Schedule: Every 15 minutes */15 * * * * /workspace/skills/crypto-sniper-oracle/reporter.py --mode alerts --symbols BTCUSDT # What it does: 1. Check for OBI spikes (>50% change) 2. Check for spread explosions (>100% increase) 3. Check for volume surges (>200% of average) 4. Send immediate Telegram alert if detected ``` --- ## 🛠️ How It Works ### **LAYER 1 — Data Acquisition (Unchanged)** Same as v3.2.1 - uses `crypto_oracle.py` to fetch data. --- ### **LAYER 2 — Report Generation (NEW)** ``` PROCEDURE Generate_Report(mode, symbols): 1. FETCH DATA FOR ALL SYMBOLS For each symbol in symbols: data[symbol] = call_oracle(symbol) 2. AGGREGATE METRICS Calculate: - How many bullish (OBI > 0.15) - How many bearish (OBI < -0.15) - Average spread across all symbols - Top movers by price change % 3. LOAD TEMPLATE template = load_template(f"{mode}_report.md") 4. POPULATE TEMPLATE report = template.format( date=now(), bullish_pairs=format_bullish(data), bearish_pairs=format_bearish(data), liquidity_summary=format_liquidity(data), top_movers=format_movers(data) ) 5. SAVE REPORT Write to /workspace/reports/{mode}_{date}.md 6. IF TELEGRAM ENABLED: send_telegram_message(report) 7. LOG EXECUTION Write to /workspace/TRADING_LOGS.md ``` --- ### **LAYER 3 — Telegram Delivery (NEW)** ``` PROCEDURE Send_Telegram_Report(report): 1. VALIDATE CREDENTIALS IF TELEGRAM_BOT_TOKEN not set: → Log error: "Telegram not configured" → ABORT IF TELEGRAM_CHAT_ID not set: → Log error: "Chat ID not configured" → ABORT 2. FORMAT MESSAGE # Telegram has 4096 char limit IF len(report) > 4000: → Split into multiple messages → Send sequentially 3. SEND VIA API POST https://api.telegram.org/bot{token}/sendMessage Body: { "chat_id": "{chat_id}", "text": "{report}", "parse_mode": "Markdown" } 4. HANDLE RESPONSE IF success: → Log: "Report sent to Telegram" IF error: → Log error details → Retry once after 5s → If still fails: Save to /workspace/failed_reports/ ``` --- ## 🔒 Security & Privacy ### **Data Collection:** - Public market data only - No authentication for Binance API - No personal data ### **Data Processing:** - All calculations local - Cache temporary (45s TTL) - Reports stored locally ### **Telegram (Optional):** - User must explicitly enable - User provides bot token + chat ID - Only sends TO user's Telegram - No data sent to third parties - Can be disabled anytime ### **Transparency:** - All Telegram sends logged - All reports archived - Full audit trail in TRADING_LOGS.md --- ## 📚 Installation & Setup ### **Basic Setup (No Telegram):** ```bash git clone https://github.com/georges91560/crypto-sniper-oracle.git cd crypto-sniper-oracle cp -r * /workspace/skills/crypto-sniper-oracle/ chmod +x /workspace/skills/crypto-sniper-oracle/*.py ``` --- ### **Telegram Setup (Optional):** **Step 1: Create Telegram Bot** ``` 1. Open Telegram, search @BotFather 2. Send: /newbot 3. Follow prompts, get BOT_TOKEN ``` **Step 2: Get Chat ID** ``` 1. Send message to your bot 2. Visit: https://api.telegram.org/bot{YOUR_TOKEN}/getUpdates 3. Find "chat":{"id":123456789} ``` **Step 3: Configure** ```bash export TELEGRAM_BOT_TOKEN="1234567890:ABCdefGHIjklMNOpqrsTUVwxyz" export TELEGRAM_CHAT_ID="123456789" ``` **Step 4: Test** ```bash python3 /workspace/skills/crypto-sniper-oracle/reporter.py --mode test ``` Expected: "✅ Test message sent to Telegram" --- ### **Cron Setup (Optional):** ```bash # Edit crontab crontab -e # Add jobs: 0 9 * * * /workspace/skills/crypto-sniper-oracle/reporter.py --mode daily 0 * * * * /workspace/skills/crypto-sniper-oracle/reporter.py --mode hourly */15 * * * * /workspace/skills/crypto-sniper-oracle/reporter.py --mode alerts ``` --- ## 📊 Usage Examples ### **Example 1: Manual Analysis** ```bash python3 crypto_oracle.py --symbol BTCUSDT ``` **Output:** JSON data (same as v3.2.1) --- ### **Example 2: Generate Report (No Telegram)** ```bash python3 reporter.py --mode daily --symbols BTCUSDT,ETHUSDT ``` **Output:** - Report saved to `/workspace/reports/daily_2026-02-27.md` - No Telegram send --- ### **Example 3: Generate + Send Telegram** ```bash # With env vars set export TELEGRAM_BOT_TOKEN="..." export TELEGRAM_CHAT_ID="..." python3 reporter.py --mode daily --symbols BTCUSDT,ETHUSDT ``` **Output:** - Report saved locally - Report sent to Telegram - Logged in TRADING_LOGS.md --- ### **Example 4: Alert Check** ```bash python3 reporter.py --mode alerts --symbols BTCUSDT ``` **If anomaly detected:** ``` 🚨 Alert sent to Telegram 📝 Logged to /workspace/reports/alerts_2026-02-27.log ``` **If no anomaly:** ``` ✅ No alerts - market normal ``` --- ## 🎯 Transparency Statement ### **What This Skill Does:** **Without Telegram:** - Fetches public data - Calculates metrics - Generates reports - Saves locally **With Telegram (User Opt-In):** - All of above PLUS - Sends reports to user's Telegram - User must provide bot token + chat ID - User can disable anytime ### **What This Skill Does NOT Do:** - Does NOT read agent memory - Does NOT intercept other skills - Does NOT trade or place orders - Does NOT access private data - Does NOT send data to third parties (except user's own Telegram if enabled) ### **Network Behavior:** **Default:** - Binance public API only **With Telegram Enabled:** - Binance public API - Telegram API (send messages only, to user's bot) --- ## 📄 License MIT License - See [LICENSE](LICENSE) --- **Version:** 3.3.0 **Security Level:** L1 (Default) / L2 (With Telegram) **Author:** Georges Andronescu (Wesley Armando) **Repository:** https://github.com/georges91560/crypto-sniper-oracle --- **END OF SKILL**

path: crypto_oracle.py
content: #!/usr/bin/env python3
"""
Crypto Sniper Oracle - Quantitative Market Data Engine
Version: 3.2.0-Enterprise
Author: Georges Andronescu (Wesley Armando) & Quant Engine
License: MIT

Fetches market data from Binance public API with:
- Order Book Imbalance (OBI) & VWAP Mathematics
- Rate limiting protection (Local Caching)
- Exponential Backoff Retry Logic
- Stale Cache Fallback
- Strict JSON Schema stdout for Agent parsing
"""

import sys
import json
import argparse
import urllib.request
import urllib.error
import logging
import time
import re
from pathlib import Path

# ==========================================
# CONFIGURATION
# ==========================================
CACHE_FILE = Path("/workspace/.oracle_cache.json")
CACHE_TTL_SECONDS = 45
MAX_RETRIES = 3
REQUEST_TIMEOUT_SECONDS = 5

# ==========================================
# LOGGER SETUP (STDERR ONLY)
# ==========================================
logging.basicConfig(
    level=logging.INFO,
    format='[%(levelname)s] %(asctime)s - %(message)s',
    handlers=[logging.StreamHandler(sys.stderr)]
)
logger = logging.getLogger(__name__)


class CacheManager:
    """Manages local file cache to prevent rate limit bans."""
    def __init__(self, cache_file: Path, ttl: int):
        self.cache_file = cache_file
        self.ttl = ttl
    
    def get(self, symbol: str) -> dict:
        try:
            if not self.cache_file.exists():
                return None
            with open(self.cache_file, 'r') as f:
                cache = json.load(f)
            
            if symbol not in cache:
                return None
            
            entry = cache[symbol]
            age = time.time() - entry['timestamp']
            
            if age <= self.ttl:
                logger.info(f"Cache hit for {symbol} (age: {age:.1f}s)")
                return entry['data']
            return None
        except Exception as e:
            logger.warning(f"Cache read error: {e}")
            return None
    
    def set(self, symbol: str, data: dict):
        try:
            cache = {}
            if self.cache_file.exists():
                with open(self.cache_file, 'r') as f:
                    cache = json.load(f)
            
            cache[symbol] = {
                'data': data,
                'timestamp': time.time()
            }
            with open(self.cache_file, 'w') as f:
                json.dump(cache, f, indent=2)
        except Exception as e:
            logger.warning(f"Cache write error: {e}")


class BinanceQuantOracle:
    BASE_URL = "https://api.binance.com/api/v3"
    
    def __init__(self, symbol: str, depth: int = 10):
        self.symbol = symbol.upper()
        self.depth = min(depth, 5000)
        self.headers = {
            'User-Agent': 'OpenClaw-Quant-Engine/3.2',
            'Accept': 'application/json'
        }
        self.cache = CacheManager(CACHE_FILE, CACHE_TTL_SECONDS)
    
    def _make_request(self, endpoint: str) -> dict:
        """HTTP request with Exponential Backoff Retry logic."""
        url = f"{self.BASE_URL}{endpoint}"
        
        for attempt in range(MAX_RETRIES):
            try:
                req = urllib.request.Request(url, headers=self.headers)
                with urllib.request.urlopen(req, timeout=REQUEST_TIMEOUT_SECONDS) as response:
                    return json.loads(response.read().decode('utf-8'))
                    
            except urllib.error.HTTPError as e:
                if e.code in [429, 418]:  # Rate Limit Exceeded
                    backoff = 2 ** attempt  # Exponential: 1s, 2s, 4s
                    logger.warning(f"Rate limit (HTTP {e.code}). Backing off for {backoff}s...")
                    time.sleep(backoff)
                    continue
                elif e.code == 400:
                    raise Exception("INVALID_SYMBOL")
                else:
                    raise Exception(f"HTTP_ERROR_{e.code}")
                    
            except urllib.error.URLError as e:
                logger.warning(f"Network error: {e.reason}. Retrying...")
                time.sleep(1)
            except Exception as e:
                raise Exception(f"SYSTEM_ERROR: {str(e)}")
                
        raise Exception("MAX_RETRIES_EXCEEDED")

    def fetch_market_state(self) -> str:
        # 1. Vérification du Cache Actif
        cached_data = self.cache.get(self.symbol)
        if cached_data:
            return json.dumps(cached_data, indent=2)
        
        try:
            logger.info(f"Fetching live quantitative data for {self.symbol}...")
            
            # 2. Appels API
            ticker_data = self._make_request(f"/ticker/24hr?symbol={self.symbol}")
            depth_data = self._make_request(f"/depth?symbol={self.symbol}&limit={self.depth}")
            
            # 3. Mathématiques Financières
            bids = [
                {"price": float(b[0]), "qty": float(b[1])} 
                for b in depth_data.get("bids", [])
            ]
            asks = [
                {"price": float(a[0]), "qty": float(a[1])} 
                for a in depth_data.get("asks", [])
            ]
            
            spread, spread_pct, spread_bps = 0.0, 0.0, 0.0
            bid_vol, ask_vol, imbalance = 0.0, 0.0, 0.0
            last_price = float(ticker_data.get("lastPrice", 0))

            if bids and asks and last_price > 0:
                best_bid, best_ask = bids[0]["price"], asks[0]["price"]
                spread = best_ask - best_bid
                spread_pct = (spread / last_price) * 100
                spread_bps = spread_pct * 100
                
                # Order Book Imbalance (OBI)
                # Positive = Buying pressure
                # Negative = Selling pressure
                bid_vol = sum(b["qty"] for b in bids)
                ask_vol = sum(a["qty"] for a in asks)
                total_vol = bid_vol + ask_vol
                imbalance = (bid_vol - ask_vol) / total_vol if total_vol > 0 else 0.0
            
            # 4. Construction du Payload
            payload = {
                "status": "success",
                "asset": self.symbol,
                "timestamp_ms": int(time.time() * 1000),
                "ticker": {
                    "last_price": round(last_price, 8),
                    "vwap_24h": round(float(ticker_data.get("weightedAvgPrice", 0)), 8),
                    "volume_24h_asset": round(float(ticker_data.get("volume", 0)), 4),
                    "volume_24h_quote": round(float(ticker_data.get("quoteVolume", 0)), 2),
                    "price_change_pct": round(float(ticker_data.get("priceChangePercent", 0)), 2),
                    "high_24h": round(float(ticker_data.get("highPrice", 0)), 8),
                    "low_24h": round(float(ticker_data.get("lowPrice", 0)), 8),
                    "trades_count_24h": int(ticker_data.get("count", 0))
                },
                "order_book": {
                    "spread_absolute": round(spread, 8),
                    "spread_bps": round(spread_bps, 2),
                    "imbalance_ratio": round(imbalance, 4),
                    "bid_volume": round(bid_vol, 4),
                    "ask_volume": round(ask_vol, 4),
                    "top_bids": bids[:5],
                    "top_asks": asks[:5]
                },
                "quant_signals": {
                    "obi_direction": "BUY_PRESSURE" if imbalance > 0.1 else ("SELL_PRESSURE" if imbalance < -0.1 else "NEUTRAL"),
                    "liquidity_quality": "EXCELLENT" if spread_bps < 5 else ("GOOD" if spread_bps < 10 else "POOR"),
                    "price_vs_vwap_pct": round(((last_price / float(ticker_data.get("weightedAvgPrice", last_price)) - 1) * 100), 2)
                }
            }
            
            # 5. Sauvegarde en Cache
            self.cache.set(self.symbol, payload)
            logger.info("Data aggregation successful.")
            return json.dumps(payload, indent=2)
            
        except Exception as e:
            error_code = str(e)
            logger.error(f"Fetch failed: {error_code}")
            
            # 6. Fallback sur le Cache Périmé (Stale Cache)
            try:
                if CACHE_FILE.exists():
                    with open(CACHE_FILE, 'r') as f:
                        cache = json.load(f)
                    if self.symbol in cache:
                        age = time.time() - cache[self.symbol]['timestamp']
                        stale_data = cache[self.symbol]['data']
                        stale_data['status'] = 'success_cached_stale'
                        stale_data['cache_age_seconds'] = int(age)
                        stale_data['warning'] = f"API unreachable. Data is {int(age)}s old."
                        logger.warning(f"Yielding stale cache (age: {int(age)}s)")
                        return json.dumps(stale_data, indent=2)
            except Exception:
                pass
            
            # 7. Erreur Fatale
            error_payload = {
                "status": "error",
                "asset": self.symbol,
                "timestamp_ms": int(time.time() * 1000),
                "error_code": error_code,
                "message": f"Failed to fetch market data: {error_code}"
            }
            return json.dumps(error_payload, indent=2)


def main():
    parser = argparse.ArgumentParser(
        description="Institutional Quant Oracle for OpenClaw",
        formatter_class=argparse.RawDescriptionHelpFormatter,
        epilog="""
Examples:
  python3 crypto_oracle.py --symbol BTCUSDT
  python3 crypto_oracle.py --symbol ETHBTC --depth 20
  python3 crypto_oracle.py --symbol SOLUSDC
        """
    )
    parser.add_argument(
        "--symbol",
        type=str,
        required=True,
        help="Trading pair (e.g., BTCUSDT, ETHBTC, BNBUSDC)"
    )
    parser.add_argument(
        "--depth",
        type=int,
        default=10,
        help="Order book depth level (default: 10, max: 5000)"
    )
    
    args = parser.parse_args()
    
    # Regex corrigée pour autoriser toutes les paires (pas juste USDT)
    # Accepte 4-12 caractères alphanumériques majuscules
    if not re.match(r'^[A-Z0-9]{4,12}$', args.symbol.upper()):
        error_output = {
            "status": "error",
            "error_code": "INVALID_FORMAT",
            "asset": args.symbol,
            "message": f"Invalid symbol format: {args.symbol}. Use 4-12 uppercase alphanumeric chars (e.g., BTCUSDT, ETHBTC)"
        }
        print(json.dumps(error_output, indent=2))
        sys.exit(1)
    
    oracle = BinanceQuantOracle(symbol=args.symbol, depth=args.depth)
    output = oracle.fetch_market_state()
    
    print(output)
    sys.exit(1 if '"status": "error"' in output else 0)


if __name__ == "__main__":
    main()


path: reporter.py
content: #!/usr/bin/env python3
"""
Crypto Sniper Oracle - Report Generator & Telegram Delivery
Version: 3.3.0
Author: Georges Andronescu (Wesley Armando)
License: MIT

Generates formatted market reports and optionally sends via Telegram.
Supports: daily reports, hourly checks, anomaly alerts, and cron jobs.
"""

import sys
import json
import argparse
import os
import subprocess
from datetime import datetime
from pathlib import Path
import urllib.request
import urllib.error

# ==========================================
# CONFIGURATION
# ==========================================
ORACLE_SCRIPT = Path("/workspace/skills/crypto-sniper-oracle/crypto_oracle.py")
TEMPLATES_DIR = Path("/workspace/skills/crypto-sniper-oracle/templates")
REPORTS_DIR = Path("/workspace/reports")
LOGS_FILE = Path("/workspace/TRADING_LOGS.md")

# Telegram (optional)
TELEGRAM_BOT_TOKEN = os.getenv("TELEGRAM_BOT_TOKEN")
TELEGRAM_CHAT_ID = os.getenv("TELEGRAM_CHAT_ID")
TELEGRAM_ENABLED = bool(TELEGRAM_BOT_TOKEN and TELEGRAM_CHAT_ID)

# ==========================================
# REPORT GENERATOR
# ==========================================

class MarketReporter:
    """Generates market analysis reports from oracle data."""
    
    def __init__(self, symbols):
        self.symbols = symbols if isinstance(symbols, list) else [symbols]
        self.data = {}
    
    def fetch_all_data(self):
        """Fetch data for all symbols using crypto_oracle.py"""
        print(f"[INFO] Fetching data for {len(self.symbols)} symbols...")
        
        for symbol in self.symbols:
            try:
                # Call oracle script
                result = subprocess.run(
                    [sys.executable, str(ORACLE_SCRIPT), "--symbol", symbol],
                    capture_output=True,
                    text=True,
                    timeout=10
                )
                
                if result.returncode == 0:
                    self.data[symbol] = json.loads(result.stdout)
                    print(f"[OK] {symbol}: Success")
                else:
                    print(f"[ERROR] {symbol}: Failed")
                    self.data[symbol] = {"status": "error", "asset": symbol}
            
            except Exception as e:
                print(f"[ERROR] {symbol}: {e}")
                self.data[symbol] = {"status": "error", "asset": symbol}
    
    def generate_daily_report(self):
        """Generate comprehensive daily market report."""
        
        # Categorize pairs
        bullish = []
        bearish = []
        neutral = []
        
        liquidity_excellent = 0
        liquidity_good = 0
        liquidity_poor = 0
        
        for symbol, data in self.data.items():
            if data.get("status") != "success":
                continue
            
            obi = data.get("order_book", {}).get("imbalance_ratio", 0)
            spread_bps = data.get("order_book", {}).get("spread_bps", 0)
            price_vs_vwap = data.get("quant_signals", {}).get("price_vs_vwap_pct", 0)
            price_change = data.get("ticker", {}).get("price_change_pct", 0)
            
            # Categorize by OBI
            if obi > 0.15:
                bullish.append({
                    "symbol": symbol,
                    "obi": obi,
                    "spread_bps": spread_bps,
                    "price_vs_vwap": price_vs_vwap,
                    "price_change": price_change
                })
            elif obi < -0.15:
                bearish.append({
                    "symbol": symbol,
                    "obi": obi,
                    "spread_bps": spread_bps,
                    "price_vs_vwap": price_vs_vwap,
                    "price_change": price_change
                })
            else:
                neutral.append(symbol)
            
            # Categorize liquidity
            if spread_bps < 5:
                liquidity_excellent += 1
            elif spread_bps < 10:
                liquidity_good += 1
            else:
                liquidity_poor += 1
        
        # Build report
        report = f"""📊 CRYPTO MARKET DAILY REPORT
{datetime.now().strftime('%Y-%m-%d %H:%M UTC')} | Powered by Wesley

━━━━━━━━━━━━━━━━━━━━━━━━━━━━

🎯 MARKET OVERVIEW ({len(self.symbols)} pairs analyzed)

"""
        
        # Bullish section
        if bullish:
            report += "🟢 BULLISH SETUPS (OBI > +0.15)\n"
            for pair in bullish:
                report += f"• {pair['symbol']}: OBI {pair['obi']:.2f}, Spread {pair['spread_bps']:.1f} bps\n"
                report += f"  Price vs VWAP: {pair['price_vs_vwap']:+.2f}%\n"
                report += f"  24h Change: {pair['price_change']:+.2f}%\n"
                report += f"  Signal: Strong buying pressure\n\n"
        else:
            report += "🟢 BULLISH SETUPS: None\n\n"
        
        # Bearish section
        if bearish:
            report += "🔴 BEARISH SETUPS (OBI < -0.15)\n"
            for pair in bearish:
                report += f"• {pair['symbol']}: OBI {pair['obi']:.2f}, Spread {pair['spread_bps']:.1f} bps\n"
                report += f"  Price vs VWAP: {pair['price_vs_vwap']:+.2f}%\n"
                report += f"  24h Change: {pair['price_change']:+.2f}%\n"
                report += f"  Signal: Selling pressure\n\n"
        else:
            report += "🔴 BEARISH SETUPS: None\n\n"
        
        # Liquidity summary
        report += "💰 LIQUIDITY QUALITY\n"
        report += f"Excellent (< 5 bps): {liquidity_excellent} pairs\n"
        report += f"Good (5-10 bps): {liquidity_good} pairs\n"
        report += f"Poor (> 10 bps): {liquidity_poor} pairs\n\n"
        
        # Top movers
        all_pairs = bullish + bearish
        if all_pairs:
            sorted_pairs = sorted(all_pairs, key=lambda x: abs(x['price_change']), reverse=True)[:3]
            report += "📈 TOP MOVERS (24h)\n"
            for pair in sorted_pairs:
                report += f"{pair['price_change']:+.1f}% {pair['symbol']}\n"
            report += "\n"
        
        # Trading opportunities
        report += "🎯 TRADING OPPORTUNITIES\n"
        if bullish:
            top_bullish = max(bullish, key=lambda x: x['obi'])
            report += f"→ {top_bullish['symbol']}: Bullish setup confirmed (OBI {top_bullish['obi']:+.2f})\n"
        if bearish:
            top_bearish = min(bearish, key=lambda x: x['obi'])
            report += f"→ {top_bearish['symbol']}: Avoid - selling pressure (OBI {top_bearish['obi']:.2f})\n"
        if not bullish and not bearish:
            report += "→ No strong setups detected. Markets neutral.\n"
        
        report += "\n━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n"
        report += f"Generated: {datetime.now().strftime('%Y-%m-%d %H:%M:%S UTC')}\n"
        report += f"Next report: Tomorrow 09:00 UTC\n"
        
        return report
    
    def generate_hourly_summary(self):
        """Generate brief hourly check."""
        
        bullish_count = 0
        bearish_count = 0
        neutral_count = 0
        
        for symbol, data in self.data.items():
            if data.get("status") != "success":
                continue
            
            obi = data.get("order_book", {}).get("imbalance_ratio", 0)
            
            if obi > 0.15:
                bullish_count += 1
            elif obi < -0.15:
                bearish_count += 1
            else:
                neutral_count += 1
        
        report = f"""⚡ HOURLY MARKET CHECK
{datetime.now().strftime('%Y-%m-%d %H:%M UTC')}

🔍 Scanned: {len(self.symbols)} pairs
🟢 Bullish: {bullish_count}
🔴 Bearish: {bearish_count}
⚪ Neutral: {neutral_count}

⚠️ Alerts: None
Next check: {datetime.now().strftime('%H')}:00 UTC
"""
        
        return report
    
    def check_anomalies(self):
        """Check for market anomalies and generate alerts."""
        
        alerts = []
        
        for symbol, data in self.data.items():
            if data.get("status") != "success":
                continue
            
            obi = data.get("order_book", {}).get("imbalance_ratio", 0)
            spread_bps = data.get("order_book", {}).get("spread_bps", 0)
            price_vs_vwap = data.get("quant_signals", {}).get("price_vs_vwap_pct", 0)
            
            # Check for OBI spike (strong signal)
            if abs(obi) > 0.20:
                alert = f"""🚨 MARKET ANOMALY DETECTED

Time: {datetime.now().strftime('%H:%M:%S UTC')}
Asset: {symbol}

📊 Anomaly Type: {"OBI SPIKE (BUY)" if obi > 0 else "OBI SPIKE (SELL)"}
• Current OBI: {obi:.2f}
• Threshold: ±0.20

💰 Liquidity: {"EXCELLENT" if spread_bps < 5 else "GOOD" if spread_bps < 10 else "POOR"} ({spread_bps:.1f} bps)
📈 Price vs VWAP: {price_vs_vwap:+.2f}%

💡 Implication:
{"Strong buying pressure detected." if obi > 0 else "Strong selling pressure detected."}
{"Potential upward movement." if obi > 0 else "Potential downward movement."}

🎯 Suggested Action:
{"Consider LONG entry if other signals align." if obi > 0 else "Consider exiting LONG positions or wait."}
"""
                alerts.append(alert)
        
        return alerts


# ==========================================
# TELEGRAM SENDER
# ==========================================

class TelegramSender:
    """Handles Telegram message delivery."""
    
    def __init__(self, bot_token, chat_id):
        self.bot_token = bot_token
        self.chat_id = chat_id
        self.api_url = f"https://api.telegram.org/bot{bot_token}/sendMessage"
    
    def send_message(self, text):
        """Send message to Telegram."""
        
        # Split if too long (Telegram 4096 char limit)
        if len(text) > 4000:
            parts = [text[i:i+4000] for i in range(0, len(text), 4000)]
        else:
            parts = [text]
        
        for part in parts:
            try:
                data = {
                    "chat_id": self.chat_id,
                    "text": part,
                    "parse_mode": "Markdown"
                }
                
                req = urllib.request.Request(
                    self.api_url,
                    data=json.dumps(data).encode('utf-8'),
                    headers={'Content-Type': 'application/json'}
                )
                
                with urllib.request.urlopen(req, timeout=10) as response:
                    result = json.loads(response.read().decode('utf-8'))
                    
                    if result.get("ok"):
                        print(f"[OK] Telegram message sent")
                    else:
                        print(f"[ERROR] Telegram API error: {result}")
            
            except Exception as e:
                print(f"[ERROR] Failed to send Telegram: {e}")


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

def main():
    parser = argparse.ArgumentParser(description="Crypto Market Reporter")
    parser.add_argument("--mode", choices=["daily", "hourly", "alerts", "test"], required=True)
    parser.add_argument("--symbols", default="BTCUSDT,ETHUSDT,SOLUSDT,BNBUSDT,ADAUSDT")
    
    args = parser.parse_args()
    
    symbols = args.symbols.split(",")
    
    # Create reporter
    reporter = MarketReporter(symbols)
    reporter.fetch_all_data()
    
    # Generate report based on mode
    if args.mode == "daily":
        report = reporter.generate_daily_report()
    elif args.mode == "hourly":
        report = reporter.generate_hourly_summary()
    elif args.mode == "alerts":
        alerts = reporter.check_anomalies()
        if alerts:
            report = "\n\n".join(alerts)
        else:
            print("[INFO] No anomalies detected")
            return
    elif args.mode == "test":
        report = "✅ Crypto Sniper Oracle - Telegram Test\n\nIf you see this, Telegram is configured correctly!"
    
    # Save report locally
    REPORTS_DIR.mkdir(parents=True, exist_ok=True)
    report_file = REPORTS_DIR / f"{args.mode}_{datetime.now().strftime('%Y-%m-%d')}.md"
    
    with open(report_file, "w") as f:
        f.write(report)
    
    print(f"[OK] Report saved to {report_file}")
    
    # Send via Telegram if enabled
    if TELEGRAM_ENABLED:
        sender = TelegramSender(TELEGRAM_BOT_TOKEN, TELEGRAM_CHAT_ID)
        sender.send_message(report)
    else:
        print("[INFO] Telegram not configured - report saved locally only")
    
    # Log execution
    log_entry = f"\n## {datetime.now().isoformat()}\n"
    log_entry += f"Mode: {args.mode}\n"
    log_entry += f"Symbols: {args.symbols}\n"
    log_entry += f"Telegram: {'Sent' if TELEGRAM_ENABLED else 'Disabled'}\n"
    log_entry += f"Report: {report_file}\n"
    
    with open(LOGS_FILE, "a") as f:
        f.write(log_entry)


if __name__ == "__main__":
    main()


path: README.md
content: # Crypto Sniper Oracle 🎯

**Institutional-grade quantitative market oracle with automated reporting**

[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
[![Version](https://img.shields.io/badge/version-3.3.0-blue.svg)](https://github.com/georges91560/crypto-sniper-oracle)
[![Python](https://img.shields.io/badge/python-3.7+-blue.svg)](https://python.org)
[![Security](https://img.shields.io/badge/security-L1%20ReadOnly-green.svg)]()

Order Book Imbalance (OBI) · VWAP Analysis · Automated Reports · Telegram Alerts

---

## 🚀 What's New in v3.3.0

✅ **Telegram Integration** (optional)  
✅ **Automated Reports** (daily, hourly, alerts)  
✅ **Cron Job Support** (scheduled monitoring)  
✅ **Report Templates** (professional formatting)  
✅ **Multi-Symbol Analysis** (aggregate reports)  

---

## 🎯 Core Features

### **1. Quantitative Analysis**
- Order Book Imbalance (OBI) detection
- VWAP divergence calculation
- Liquidity scoring (spread in bps)
- Composite risk scoring (0-100)

### **2. Automated Reporting**
- Daily market summaries
- Hourly status checks
- Real-time anomaly alerts
- Multi-symbol aggregation

### **3. Telegram Delivery (Optional)**
- Sends reports to your Telegram
- Configurable (opt-in)
- Instant alerts on anomalies
- Full message history

---

## 📊 Usage Modes

### **Mode 1: Manual Analysis**

```bash
python3 crypto_oracle.py --symbol BTCUSDT
```

**Output:** JSON data with OBI, VWAP, spread

---

### **Mode 2: Generate Report (No Telegram)**

```bash
python3 reporter.py --mode daily --symbols BTCUSDT,ETHUSDT,SOLUSDT
```

**Output:** 
- Formatted report saved to `/workspace/reports/daily_2026-02-27.md`
- No Telegram delivery

---

### **Mode 3: Automated Reports + Telegram**

**Setup:**
```bash
export TELEGRAM_BOT_TOKEN="your_bot_token"
export TELEGRAM_CHAT_ID="your_chat_id"

python3 reporter.py --mode daily --symbols BTCUSDT,ETHUSDT
```

**Output:**
- Report saved locally
- Report sent to Telegram
- Logged to TRADING_LOGS.md

---

### **Mode 4: Cron Jobs (Fully Automated)**

```bash
# Daily report at 9am UTC
0 9 * * * /workspace/skills/crypto-sniper-oracle/reporter.py --mode daily

# Hourly check
0 * * * * /workspace/skills/crypto-sniper-oracle/reporter.py --mode hourly

# Alerts every 15min
*/15 * * * * /workspace/skills/crypto-sniper-oracle/reporter.py --mode alerts
```

---

## 📋 Report Examples

### **Daily Report**

```markdown
📊 CRYPTO MARKET DAILY REPORT
2026-02-27 09:00 UTC | Powered by Wesley

━━━━━━━━━━━━━━━━━━━━━━━━━━━━

🎯 MARKET OVERVIEW (5 pairs analyzed)

🟢 BULLISH SETUPS (OBI > +0.15)
• BTCUSDT: OBI +0.18, Spread 2.1 bps
  Price vs VWAP: +0.5%
  24h Change: +3.2%
  Signal: Strong buying pressure

• ETHUSDT: OBI +0.12, Spread 3.5 bps
  Price vs VWAP: +0.3%
  24h Change: +2.1%
  Signal: Strong buying pressure

🔴 BEARISH SETUPS (OBI < -0.15)
• SOLUSDT: OBI -0.16, Spread 8.2 bps
  Price vs VWAP: -0.8%
  24h Change: -4.5%
  Signal: Selling pressure

💰 LIQUIDITY QUALITY
Excellent (< 5 bps): 3 pairs
Good (5-10 bps): 1 pairs
Poor (> 10 bps): 1 pairs

📈 TOP MOVERS (24h)
-4.5% SOLUSDT
+3.2% BTCUSDT
+2.1% ETHUSDT

🎯 TRADING OPPORTUNITIES
→ BTCUSDT: Bullish setup confirmed (OBI +0.18)
→ SOLUSDT: Avoid - selling pressure (OBI -0.16)

━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Generated: 2026-02-27 09:00:00 UTC
Next report: 2026-02-28 09:00:00 UTC
```

---

### **Anomaly Alert**

```markdown
🚨 MARKET ANOMALY DETECTED

Time: 15:23:45 UTC
Asset: BTCUSDT

📊 Anomaly Type: OBI SPIKE (BUY)
• Current OBI: +0.22
• Threshold: ±0.20

💰 Liquidity: EXCELLENT (2.3 bps)
📈 Price vs VWAP: +0.6%

💡 Implication:
Strong buying pressure detected.
Potential upward movement.

🎯 Suggested Action:
Consider LONG entry if other signals align.
```

---

## 🔧 Installation

### **Step 1: Clone Repository**

```bash
git clone https://github.com/georges91560/crypto-sniper-oracle.git
cd crypto-sniper-oracle
```

### **Step 2: Copy to Workspace**

```bash
mkdir -p /workspace/skills/crypto-sniper-oracle

cp crypto_oracle.py /workspace/skills/crypto-sniper-oracle/
cp reporter.py /workspace/skills/crypto-sniper-oracle/
cp SKILL.md /workspace/skills/crypto-sniper-oracle/

chmod +x /workspace/skills/crypto-sniper-oracle/*.py
```

### **Step 3: Test**

```bash
# Test data fetcher
python3 /workspace/skills/crypto-sniper-oracle/crypto_oracle.py --symbol BTCUSDT

# Test reporter
python3 /workspace/skills/crypto-sniper-oracle/reporter.py --mode daily --symbols BTCUSDT
```

---

## 📱 Telegram Setup (Optional)

### **Step 1: Create Bot**

1. Open Telegram
2. Search `@BotFather`
3. Send `/newbot`
4. Follow prompts
5. Save **BOT_TOKEN**

### **Step 2: Get Chat ID**

1. Send a message to your bot
2. Visit: `https://api.telegram.org/bot{YOUR_TOKEN}/getUpdates`
3. Find `"chat":{"id":123456789}`
4. Save **CHAT_ID**

### **Step 3: Configure**

```bash
export TELEGRAM_BOT_TOKEN="1234567890:ABCdefGHIjklMNOpqrsTUVwxyz"
export TELEGRAM_CHAT_ID="123456789"
```

### **Step 4: Test**

```bash
python3 /workspace/skills/crypto-sniper-oracle/reporter.py --mode test
```

**Expected:** Message in Telegram: "✅ Telegram Test"

---

## ⏰ Cron Setup (Optional)

### **Edit Crontab**

```bash
crontab -e
```

### **Add Jobs**

```bash
# Daily report at 9am UTC
0 9 * * * /workspace/skills/crypto-sniper-oracle/reporter.py --mode daily --symbols BTCUSDT,ETHUSDT,SOLUSDT,BNBUSDT,ADAUSDT

# Hourly check
0 * * * * /workspace/skills/crypto-sniper-oracle/reporter.py --mode hourly --symbols BTCUSDT,ETHUSDT

# Alerts every 15 minutes
*/15 * * * * /workspace/skills/crypto-sniper-oracle/reporter.py --mode alerts --symbols BTCUSDT,ETHUSDT,SOLUSDT
```

### **Verify**

```bash
crontab -l
```

---

## 📊 Metrics Explained

### **OBI (Order Book Imbalance)**

```
Formula: (Bid Volume - Ask Volume) / Total Volume

+0.20 or higher → Strong buy pressure
+0.10 to +0.20 → Moderate buy pressure
-0.10 to +0.10 → Neutral
-0.20 to -0.10 → Moderate sell pressure
-0.20 or lower → Strong sell pressure
```

### **VWAP Divergence**

```
Price vs 24h Volume-Weighted Average

> +1.0% → Overextended above average
+0.2 to +1.0% → Bullish strength
-0.2 to +0.2% → Fair value
< -1.0% → Oversold
```

### **Spread (Basis Points)**

```
< 5 bps → Excellent liquidity
5-10 bps → Good liquidity
10-30 bps → Moderate (slippage risk)
> 30 bps → Poor (avoid)
```

---

## 📁 File Structure

```
crypto-sniper-oracle/
├── crypto_oracle.py       # Data fetcher
├── reporter.py            # Report generator
├── SKILL.md               # Skill definition
├── README.md              # This file
├── CONFIGURATION.md       # Setup guide
└── LICENSE                # MIT License
```

**Created by skill:**
```
/workspace/
├── .oracle_cache.json           # Cache (45s TTL)
├── TRADING_LOGS.md              # Execution logs
└── reports/
    ├── daily_2026-02-27.md      # Daily reports
    ├── hourly_2026-02-27.md     # Hourly summaries
    └── alerts_2026-02-27.log    # Alert history
```

---

## 🔒 Security & Privacy

### **Data Collection**
- ✅ Public market data only
- ❌ No authentication required
- ❌ No personal data

### **Telegram (Optional)**
- ✅ User must explicitly enable
- ✅ User provides bot token + chat ID
- ✅ Sends ONLY to user's Telegram
- ❌ No third-party data sharing

### **Network Access**
- ✅ Binance public API
- ✅ Telegram API (if enabled)
- ❌ No other endpoints

---

## 🐛 Troubleshooting

### **Telegram not sending**

**Check:**
```bash
echo $TELEGRAM_BOT_TOKEN
echo $TELEGRAM_CHAT_ID
```

**Test:**
```bash
python3 reporter.py --mode test
```

### **Cron not running**

**Check logs:**
```bash
grep CRON /var/log/syslog
```

**Verify paths:**
```bash
which python3
# Use full path in crontab
```

### **Reports not generated**

**Check permissions:**
```bash
ls -la /workspace/reports/
chmod 755 /workspace/reports/
```

---

## 📄 License

MIT License - See [LICENSE](LICENSE)

---

## 👤 Author

**Georges Andronescu (Wesley Armando)**

- GitHub: [@georges91560](https://github.com/georges91560)
- Repository: [crypto-sniper-oracle](https://github.com/georges91560/crypto-sniper-oracle)

---

**Quantitative analysis + Automated reporting = Data-driven decisions.** 🎯


path: CONFIGURATION.md
content: # Configuration Guide

**Crypto Sniper Oracle v3.3.0 - Complete Setup**

---

## Quick Start

### **Minimum Setup (No Telegram)**

```bash
git clone https://github.com/georges91560/crypto-sniper-oracle.git
cp -r crypto-sniper-oracle/* /workspace/skills/crypto-sniper-oracle/
chmod +x /workspace/skills/crypto-sniper-oracle/*.py
```

**Test:**
```bash
python3 /workspace/skills/crypto-sniper-oracle/crypto_oracle.py --symbol BTCUSDT
```

---

## Telegram Setup (Optional)

### **Step 1: Create Telegram Bot**

1. **Open Telegram app**
2. **Search:** `@BotFather`
3. **Send:** `/newbot`
4. **Follow prompts:**
   - Bot name: `Crypto Sniper Bot` (or your choice)
   - Bot username: `your_crypto_sniper_bot` (must end in `bot`)
5. **Save the BOT_TOKEN:**
   ```
   [REDACTED_SECRET]
   ```

---

### **Step 2: Get Your Chat ID**

**Method 1: Via API**
1. Send any message to your bot
2. Visit (replace YOUR_TOKEN):
   ```
   https://api.telegram.org/botYOUR_TOKEN/getUpdates
   ```
3. Look for:
   ```json
   "chat": {
     "id": 123456789
   }
   ```

**Method 2: Via @userinfobot**
1. Search `@userinfobot` in Telegram
2. Start chat
3. It will show your Chat ID

---

### **Step 3: Set Environment Variables**

**Temporary (current session):**
```bash
export TELEGRAM_BOT_TOKEN="[REDACTED_SECRET]"
export TELEGRAM_CHAT_ID="123456789"
```

**Permanent (add to ~/.bashrc or ~/.profile):**
```bash
echo 'export TELEGRAM_BOT_TOKEN="1234567890:ABCdefGHIjklMNOpqrsTUVwxyz"' >> ~/.bashrc
echo 'export TELEGRAM_CHAT_ID="123456789"' >> ~/.bashrc
source ~/.bashrc
```

---

### **Step 4: Test Telegram**

```bash
python3 /workspace/skills/crypto-sniper-oracle/reporter.py --mode test
```

**Expected output:**
```
[INFO] Fetching data for 0 symbols...
[OK] Report saved to /workspace/reports/test_2026-02-27.md
[OK] Telegram message sent
```

**Expected in Telegram:**
```
✅ Crypto Sniper Oracle - Telegram Test

If you see this, Telegram is configured correctly!
```

---

## Cron Jobs Setup (Optional)

### **Editing Crontab**

```bash
crontab -e
```

If first time, select editor (nano recommended).

---

### **Recommended Cron Jobs**

**Add these lines to crontab:**

```bash
# Daily market report at 9am UTC
0 9 * * * /usr/bin/python3 /workspace/skills/crypto-sniper-oracle/reporter.py --mode daily --symbols BTCUSDT,ETHUSDT,SOLUSDT,BNBUSDT,ADAUSDT

# Hourly status check
0 * * * * /usr/bin/python3 /workspace/skills/crypto-sniper-oracle/reporter.py --mode hourly --symbols BTCUSDT,ETHUSDT,SOLUSDT

# Anomaly alerts every 15 minutes
*/15 * * * * /usr/bin/python3 /workspace/skills/crypto-sniper-oracle/reporter.py --mode alerts --symbols BTCUSDT,ETHUSDT,SOLUSDT

# Weekly summary (Sunday 18:00 UTC)
0 18 * * 0 /usr/bin/python3 /workspace/skills/crypto-sniper-oracle/reporter.py --mode daily --symbols BTCUSDT,ETHUSDT,SOLUSDT,BNBUSDT,ADAUSDT,DOTUSDT,LINKUSDT,MATICUSDT,AVAXUSDT,UNIUSDT
```

**Important:** Use FULL paths (`/usr/bin/python3`, not just `python3`)

---

### **Find Python Path**

```bash
which python3
# Output: /usr/bin/python3
```

---

### **Verify Cron Jobs**

```bash
# List all cron jobs
crontab -l

# Check cron logs
grep CRON /var/log/syslog
```

---

## Configuration Options

### **Environment Variables**

```bash
# Telegram (optional)
TELEGRAM_BOT_TOKEN="your_bot_token"
TELEGRAM_CHAT_ID="your_chat_id"

# Cache TTL (optional, default: 45s)
ORACLE_CACHE_TTL="45"

# Logging (optional, default: INFO)
ORACLE_LOG_LEVEL="INFO"
```

---

### **Reporter Arguments**

```bash
python3 reporter.py [OPTIONS]

Options:
  --mode {daily|hourly|alerts|test}
        Report mode (required)
  
  --symbols SYMBOL1,SYMBOL2,...
        Comma-separated list of trading pairs
        Default: BTCUSDT,ETHUSDT,SOLUSDT,BNBUSDT,ADAUSDT

Examples:
  # Daily report for 5 pairs
  reporter.py --mode daily --symbols BTCUSDT,ETHUSDT,SOLUSDT,BNBUSDT,ADAUSDT
  
  # Hourly check for BTC only
  reporter.py --mode hourly --symbols BTCUSDT
  
  # Alerts for top 3 pairs
  reporter.py --mode alerts --symbols BTCUSDT,ETHUSDT,SOLUSDT
```

---

## Testing

### **Test Data Fetcher**

```bash
python3 crypto_oracle.py --symbol BTCUSDT
```

**Expected:** JSON output with OBI, VWAP, spread

---

### **Test Reporter (No Telegram)**

```bash
# Unset Telegram vars
unset TELEGRAM_BOT_TOKEN
unset TELEGRAM_CHAT_ID

python3 reporter.py --mode daily --symbols BTCUSDT,ETHUSDT
```

**Expected:**
- Report saved to `/workspace/reports/daily_YYYY-MM-DD.md`
- No Telegram delivery

---

### **Test Reporter (With Telegram)**

```bash
# Set Telegram vars
export TELEGRAM_BOT_TOKEN="..."
export TELEGRAM_CHAT_ID="..."

python3 reporter.py --mode daily --symbols BTCUSDT,ETHUSDT
```

**Expected:**
- Report saved locally
- Report sent to Telegram

---

## File Locations

```
/workspace/
├── skills/crypto-sniper-oracle/
│   ├── crypto_oracle.py       # Data fetcher
│   ├── reporter.py            # Report generator
│   └── SKILL.md               # Skill definition
├── .oracle_cache.json         # Cache (auto-created)
├── TRADING_LOGS.md            # Execution logs (auto-created)
└── reports/                   # Reports directory (auto-created)
    ├── daily_2026-02-27.md
    ├── hourly_2026-02-27.md
    └── alerts_2026-02-27.log
```

---

## Permissions

### **Make Scripts Executable**

```bash
chmod +x /workspace/skills/crypto-sniper-oracle/crypto_oracle.py
chmod +x /workspace/skills/crypto-sniper-oracle/reporter.py
```

### **Create Reports Directory**

```bash
mkdir -p /workspace/reports
chmod 755 /workspace/reports
```

---

## Troubleshooting

### **"No module named ..."**

**Problem:** Missing Python dependencies

**Solution:**
This skill uses ONLY standard library. No pip install needed.

---

### **"Telegram message not sent"**

**Checklist:**
1. Verify bot token: `echo $TELEGRAM_BOT_TOKEN`
2. Verify chat ID: `echo $TELEGRAM_CHAT_ID`
3. Test connectivity:
   ```bash
   curl https://api.telegram.org/bot$TELEGRAM_BOT_TOKEN/getMe
   ```
4. Run test:
   ```bash
   python3 reporter.py --mode test
   ```

---

### **"Cron job not running"**

**Checklist:**
1. **Use full paths:**
   ```bash
   # WRONG
   */15 * * * * reporter.py --mode alerts
   
   # CORRECT
   */15 * * * * /usr/bin/python3 /workspace/skills/crypto-sniper-oracle/reporter.py --mode alerts
   ```

2. **Check cron logs:**
   ```bash
   grep CRON /var/log/syslog | tail -20
   ```

3. **Test command manually:**
   ```bash
   /usr/bin/python3 /workspace/skills/crypto-sniper-oracle/reporter.py --mode daily
   ```

4. **Verify crontab syntax:**
   ```bash
   crontab -l
   ```

---

### **"Rate limit exceeded"**

**Problem:** Too many API calls to Binance

**Solution:**
- Cache prevents most rate limits (45s TTL)
- Don't query same symbol < 45s apart
- Spread out cron jobs (not all at same time)

---

### **"Report file not created"**

**Problem:** Permissions or path issue

**Solution:**
```bash
# Check directory exists
ls -la /workspace/reports/

# Create if needed
mkdir -p /workspace/reports

# Fix permissions
chmod 755 /workspace/reports
```

---

## Advanced Configuration

### **Custom Symbols List**

Create file `/workspace/my_symbols.txt`:
```
BTCUSDT
ETHUSDT
SOLUSDT
BNBUSDT
ADAUSDT
```

Use in cron:
```bash
0 9 * * * /usr/bin/python3 /workspace/skills/crypto-sniper-oracle/reporter.py --mode daily --symbols $(cat /workspace/my_symbols.txt | tr '\n' ',')
```

---

### **Multiple Telegram Destinations**

Send to multiple chats:
```bash
# Export multiple chat IDs
export TELEGRAM_CHAT_ID_MAIN="123456789"
export TELEGRAM_CHAT_ID_ALERTS="987654321"

# Modify reporter.py to send to both
```

---

### **Custom Report Templates**

Create `/workspace/skills/crypto-sniper-oracle/templates/custom_daily.md`

Modify `reporter.py` to use custom template.

---

## Best Practices

### ✅ **Do:**

- Test Telegram before enabling cron
- Use full paths in crontab
- Monitor logs regularly
- Archive old reports monthly
- Review anomaly alerts promptly

### ❌ **Don't:**

- Spam Telegram (respect rate limits)
- Run multiple identical cron jobs
- Delete TRADING_LOGS.md (audit trail)
- Share bot token publicly
- Ignore persistent errors

---

## Support

**Issues:** https://github.com/georges91560/crypto-sniper-oracle/issues  
**Documentation:** https://github.com/georges91560/crypto-sniper-oracle

---

**END OF CONFIGURATION GUIDE**


Security scan verdicts — ClawScan: clean | static analysis: clean | VirusTotal: clean | SkillSpector: suspicious (HIGH)