MidasBot: bot trading crypto IA + stratégies Ichimoku validées
- Infra: Freqtrade (futures dry-run) + Redis + dashboard + Docker Compose - Couche IA: ai_analyzer (Claude via abonnement, MCP TradingView, backfill biais) - Stratégies: SampleStrategy, AiBiasStrategy, IchimokuLS (long/short, validée train/test + données vierges + walk-forward), MTFIchimoku, variantes hyperopt - Arbitrage CEX (dry-run), backtesting, walk-forward, volatility targeting - IchimokuLS en dry-run live (config_live.json) Claude-Session: https://claude.ai/code/session_01VHETcFacdnDhQzthLpdYFR
This commit is contained in:
92
ai_analyzer/analyzer.py
Normal file
92
ai_analyzer/analyzer.py
Normal file
@@ -0,0 +1,92 @@
|
||||
"""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()
|
||||
Reference in New Issue
Block a user