Files
MidasBot/ai_analyzer/backfill.py
jerem 633b033f4d 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
2026-06-23 19:25:49 +02:00

112 lines
4.1 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""Backfill — génère un historique de biais IA pour backtester la stratégie.
Parcourt l'historique des bougies à une cadence donnée et, à chaque pas de temps,
demande à Claude un biais en n'utilisant QUE les données disponibles jusqu'à ce
moment-là (pas de fuite du futur). Écrit chaque biais dans l'historique CSV avec
l'horodatage de la bougie correspondante.
⚠️ COÛTEUX EN QUOTA D'ABONNEMENT : 1 appel Claude par pas de temps.
6 mois × cadence 24 h ≈ 180 appels. Choisis une cadence raisonnable.
Usage :
python backfill.py --start 20260101 --step-hours 24
python backfill.py --start 20260101 --end 20260301 --step-hours 12 --pairs BTC/USDT,ETH/USDT
"""
from __future__ import annotations
import argparse
import os
from datetime import datetime, timedelta, timezone
import ccxt
from claude_client import ClaudeClient
from market_data import snapshot_from_candles
from signal_store import append_history
EXCHANGE = os.environ.get("ANALYZER_EXCHANGE", "binance")
MODEL = os.environ.get("ANALYZER_MODEL", "claude-sonnet-4-6")
HISTORY_DIR = os.environ.get(
"ANALYZER_HISTORY_DIR",
os.path.join(os.path.dirname(os.path.dirname(__file__)),
"freqtrade", "user_data", "ai_bias_history"),
)
WINDOW = 100 # nb de bougies fournies à Claude à chaque pas
def _parse_day(s: str) -> datetime:
return datetime.strptime(s, "%Y%m%d").replace(tzinfo=timezone.utc)
def _fetch_full(exchange, pair: str, timeframe: str, since_ms: int) -> list:
"""Récupère tout l'OHLCV depuis `since_ms` (pagination ccxt)."""
out: list = []
cursor = since_ms
while True:
batch = exchange.fetch_ohlcv(pair, timeframe=timeframe, since=cursor, limit=1000)
if not batch:
break
out += batch
cursor = batch[-1][0] + 1
if len(batch) < 1000:
break
return out
def main() -> None:
p = argparse.ArgumentParser(description="MidasBot — backfill historique des biais IA")
p.add_argument("--pairs", default="BTC/USDT,ETH/USDT,SOL/USDT,BNB/USDT")
p.add_argument("--timeframe", default="1h")
p.add_argument("--start", required=True, help="AAAAMMJJ")
p.add_argument("--end", default=None, help="AAAAMMJJ (défaut: maintenant)")
p.add_argument("--step-hours", type=int, default=24, help="cadence d'analyse")
p.add_argument("--yes", action="store_true", help="ne pas demander confirmation")
args = p.parse_args()
pairs = [x.strip() for x in args.pairs.split(",") if x.strip()]
tf = args.timeframe
start = _parse_day(args.start)
end = _parse_day(args.end) if args.end else datetime.now(timezone.utc)
step = timedelta(hours=args.step_hours)
n_steps = int((end - start) / step)
print(f"Backfill {pairs} {tf} | {start.date()}{end.date()} | "
f"pas {args.step_hours} h | ~{n_steps} appels Claude ({MODEL})")
if not args.yes:
if input("Continuer ? Ça consomme ton quota d'abonnement [y/N] ").strip().lower() != "y":
print("Annulé.")
return
exchange = getattr(ccxt, EXCHANGE)({"enableRateLimit": True})
since_ms = int(start.timestamp() * 1000)
# Récupère tout l'historique une fois par paire (puis on tranche par pas de temps).
full = {pair: _fetch_full(exchange, pair, tf, since_ms) for pair in pairs}
client = ClaudeClient(model=MODEL)
t = start
done = 0
while t <= end:
t_ms = int(t.timestamp() * 1000)
snaps = []
for pair in pairs:
candles = [c for c in full[pair] if c[0] <= t_ms][-WINDOW:]
snap = snapshot_from_candles(pair, tf, candles)
if snap:
snaps.append(snap)
if snaps:
try:
batch = client.get_biases(snaps)
for bias in batch.biases:
append_history(bias, HISTORY_DIR, ts=t)
done += 1
print(f" {t.isoformat()}{len(batch.biases)} biais")
except Exception as exc: # noqa: BLE001
print(f" {t.isoformat()} → erreur: {exc}")
t += step
print(f"Terminé : {done} pas écrits dans {HISTORY_DIR}")
if __name__ == "__main__":
main()