"""Boucle d'analyse : marché -> Claude -> biais dans Redis. Cadence VOLONTAIREMENT basse (1 cycle par bougie sur timeframe >= 15 min) : l'usage automatisé d'un abonnement a des limites ; un cycle = UN seul appel Claude couvrant toutes les paires (batch), pour économiser le quota. Usage : python analyzer.py --once # un seul cycle (test) python analyzer.py # boucle continue """ from __future__ import annotations import argparse import os import time from datetime import datetime, timezone from pathlib import Path from claude_client import ClaudeClient, ClaudeError from market_data import build_snapshots from signal_store import append_history, write_bias _PROJECT_ROOT = Path(__file__).resolve().parent.parent # --- Configuration via variables d'environnement --- EXCHANGE = os.environ.get("ANALYZER_EXCHANGE", "binance") PAIRS = os.environ.get("ANALYZER_PAIRS", "BTC/USDT,ETH/USDT,SOL/USDT,BNB/USDT").split(",") TIMEFRAME = os.environ.get("ANALYZER_TIMEFRAME", "1h") INTERVAL_S = int(os.environ.get("ANALYZER_INTERVAL_S", "3600")) # 1 h par défaut MODEL = os.environ.get("ANALYZER_MODEL", "claude-sonnet-4-6") MCP_CONFIG = os.environ.get("ANALYZER_MCP_CONFIG") # ex. "/app/.mcp.json" ALLOWED_TOOLS = os.environ.get("ANALYZER_ALLOWED_TOOLS") # ex. "mcp__tradingview" # Historique horodaté (pour backtester l'IA). Lu par AiBiasStrategy en backtest. HISTORY_DIR = os.environ.get( "ANALYZER_HISTORY_DIR", str(_PROJECT_ROOT / "freqtrade" / "user_data" / "ai_bias_history"), ) def _log(msg: str) -> None: ts = datetime.now(timezone.utc).strftime("%Y-%m-%d %H:%M:%S") print(f"[analyzer {ts}] {msg}", flush=True) def run_cycle(client: ClaudeClient) -> int: pairs = [p.strip() for p in PAIRS if p.strip()] _log(f"Instantané {EXCHANGE} {TIMEFRAME} pour {pairs}…") snapshots = build_snapshots(EXCHANGE, pairs, timeframe=TIMEFRAME) if not snapshots: _log("Aucun instantané récupéré — cycle ignoré.") return 0 _log(f"Appel Claude ({MODEL}) pour {len(snapshots)} paire(s)…") batch = client.get_biases(snapshots) written = 0 ts = datetime.now(timezone.utc) for bias in batch.biases: write_bias(bias) # état courant (live/dry-run) append_history(bias, HISTORY_DIR, ts) # trace horodatée (backtest IA) written += 1 _log( f" → {bias.pair}: {bias.direction} (conf={bias.confidence:.2f}) — {bias.rationale}" ) _log(f"{written} biais écrit(s) dans Redis + historique ({HISTORY_DIR}).") return written def main() -> None: parser = argparse.ArgumentParser(description="MidasBot — analyzer IA") parser.add_argument("--once", action="store_true", help="un seul cycle puis sortie") args = parser.parse_args() client = ClaudeClient(model=MODEL, mcp_config=MCP_CONFIG, allowed_tools=ALLOWED_TOOLS) if args.once: run_cycle(client) return _log(f"Démarrage boucle (intervalle {INTERVAL_S}s).") while True: try: run_cycle(client) except ClaudeError as exc: _log(f"Erreur Claude : {exc}") except Exception as exc: # noqa: BLE001 _log(f"Erreur inattendue : {exc}") time.sleep(INTERVAL_S) if __name__ == "__main__": main()