Nexo-S commited on
Commit
ebc5d12
·
verified ·
1 Parent(s): 236992b

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +106 -261
app.py CHANGED
@@ -1,4 +1,4 @@
1
- # --- 🏴‍☠️ MONKEY PATCH : FIX HF_FOLDER ERROR ---
2
  import huggingface_hub
3
  try:
4
  from huggingface_hub import HfFolder
@@ -24,27 +24,25 @@ import aiohttp
24
  from types import ModuleType
25
  import yfinance as yf
26
 
27
- # --- 🦖 IMPORT LIGHTGBM (LE NOUVEAU MOTEUR) ---
28
  try:
29
  import lightgbm as lgb
30
  LGBM_AVAILABLE = True
31
  except ImportError:
32
  LGBM_AVAILABLE = False
33
- print("⚠️ LightGBM non installé. Lance: pip install lightgbm")
34
 
35
  try:
36
  import MetaTrader5 as mt5
37
  MT5_AVAILABLE = True
38
  except ImportError:
39
  MT5_AVAILABLE = False
40
- print("🌐 [CLOUD MODE] MetaTrader5 non détecté. Bascule sur CCXT.")
41
 
42
  # --- 🥷 NINJA HACK : MOCK PANDAS_TA ---
43
  if "pandas_ta" not in sys.modules:
44
  mock_ta = ModuleType("pandas_ta")
45
  sys.modules["pandas_ta"] = mock_ta
46
- print("🥷 Pandas-TA neutralisé (Mock actif).")
47
-
48
  if not hasattr(pd.DataFrame, "ta"):
49
  class FakeTA:
50
  def __getattr__(self, name): return lambda *args, **kwargs: None
@@ -75,21 +73,38 @@ exchange_sync = ccxt.kucoin({"enableRateLimit": True, "timeout": 30000})
75
 
76
  market_cache, last_fetch_time = {}, {}
77
  CACHE_DURATION = 300
78
- DREAM_MODE_ACTIVE = True # 🌙 Contrôle du Sommeil
79
 
80
  try:
81
  from sentiment_engine import get_crypto_sentiment
82
- print("✅ Sentiment Engine : Connecté.")
83
  except:
84
  async def get_crypto_sentiment(symbol): return 0.5
85
  try:
86
  from ensemble import combine_scores
87
  except:
88
- def combine_scores(s, t, m, l, sent, r): return (t+m+l+sent)/4, 0.25, 0.25, 0.25, 0.25
89
 
90
- # --- DB & SYNC (V30 DINOSAURE) ---
91
- DB_NAME = "alphatrade_v30_dino.db" # 🦖 RESET DB POUR L'ADN
92
  HF_TOKEN = os.environ.get("HF_TOKEN")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
93
 
94
  def init_db():
95
  try:
@@ -103,9 +118,7 @@ def init_db():
103
 
104
  cursor = conn.cursor()
105
  cursor.execute("PRAGMA table_info(agent_logic)")
106
- al_cols = [col[1] for col in cursor.fetchall()]
107
-
108
- if not al_cols:
109
  conn.execute('''CREATE TABLE IF NOT EXISTS agent_logic (
110
  symbol TEXT, timeframe TEXT, tp_mult REAL, sl_mult REAL,
111
  score REAL, last_pnl REAL, min_prob REAL, min_tp_dist REAL,
@@ -122,8 +135,7 @@ def init_db():
122
  ('ALL', '4h', 3.0, 2.0, 0, 0, 0.50, 0.008, 1, 0, 0)
123
  ]
124
  conn.executemany("INSERT INTO agent_logic VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", defaults)
125
- print("✅ Base de données V30 (Dinosaure) opérationnelle.")
126
- except Exception as e: print(f"❌ Erreur critique DB: {e}")
127
 
128
  async def save_to_db(data):
129
  try:
@@ -132,9 +144,19 @@ async def save_to_db(data):
132
  conn.commit()
133
  except Exception as e: print(f"❌ DB Error : {e}")
134
 
135
- # --- INITIALISATION DB ---
136
- restore_db_from_hf() # ⬅️ 1. On télécharge la sauvegarde
137
- init_db() # ⬅️ 2. Ensuite on vérifie que les tables existent bien
 
 
 
 
 
 
 
 
 
 
138
 
139
  def memory_guard():
140
  if psutil.virtual_memory().percent > 80:
@@ -164,19 +186,15 @@ try:
164
  time_model = joblib.load("time_model.pkl")
165
  regime_model = joblib.load("regime_model.pkl")
166
  regime_scaler = joblib.load("regime_scaler.pkl")
167
- print("✅ Cerveaux Classiques OK.")
168
  except Exception as e: print(f"⚠️ Erreur IA Classique : {e}")
169
 
170
  try:
171
  dino_brain = lgb.Booster(model_file='dino_lgbm_model.txt') if LGBM_AVAILABLE else None
172
- if dino_brain: print("🦖 Cerveau LightGBM chargé.")
173
  except:
174
  dino_brain = None
175
- print("⚠️ Modèle Dino non trouvé, utilisation de l'ensemble classique.")
176
 
177
  # --- 📊 FEATURES ENGINE ---
178
  async def fetch_kucoin_futures_data(symbol):
179
- """Récupère l'OI et le CVD via KuCoin Futures API"""
180
  try:
181
  ku_sym = symbol.replace("/", "").replace("BTC", "XBT") + "M"
182
  async with aiohttp.ClientSession() as session:
@@ -184,8 +202,7 @@ async def fetch_kucoin_futures_data(symbol):
184
  trade_url = f"https://api-futures.kucoin.com/api/v1/trade/history?symbol={ku_sym}"
185
  async with session.get(oi_url) as r1, session.get(trade_url) as r2:
186
  oi_json = await r1.json()
187
- trade_json = await r2.json()
188
- trades = trade_json.get("data", [])
189
  cvd = sum([float(t.get("size", 0)) if t.get("side") == "buy" else -float(t.get("size", 0)) for t in trades])
190
  return {"oi": float(oi_json.get("data", {}).get("value", 0)), "cvd": cvd}
191
  except: return {"oi": 0, "cvd": 0}
@@ -198,25 +215,16 @@ def prepare_features_sync(symbol, timeframe='1h', limit_bars=600):
198
  if cache_key in market_cache and now - last_fetch_time.get(cache_key, 0) < CACHE_DURATION:
199
  df = market_cache[cache_key].copy()
200
  else:
201
- if "XAU" in symbol.upper():
202
- ticker = "GC=F"
203
- yf_map = {"1m":"1m", "5m":"5m", "15m":"15m", "1h":"1h", "4h":"1h", "1d":"1d"}
204
- data = yf.download(ticker, period="5d", interval=yf_map.get(timeframe, "1h"), progress=False)
205
- if data.empty: return pd.DataFrame()
206
- df = data.reset_index().iloc[:, [0, 1, 2, 3, 4, 6]]
207
- df.columns = ['ts', 'open', 'high', 'low', 'close', 'vol']
208
- else:
209
- fetch_symbol = symbol if "/USDT" in symbol else symbol.replace("/USD", "/USDT")
210
- if "/" not in fetch_symbol: fetch_symbol += "/USDT"
211
-
212
- # 🛡️ TRIPLE CHECK KUCOIN
213
- df = pd.DataFrame()
214
- for attempt in range(3):
215
- try:
216
- bars = exchange_sync.fetch_ohlcv(fetch_symbol, timeframe, limit=limit_bars)
217
- df = pd.DataFrame(bars, columns=['ts', 'open', 'high', 'low', 'close', 'vol'])
218
- if not df.empty: break
219
- except: time.sleep(2)
220
 
221
  if df.empty: return pd.DataFrame()
222
  market_cache[cache_key], last_fetch_time[cache_key] = df.copy(), now
@@ -271,21 +279,17 @@ async def predict_signal(symbol, timeframe="1h"):
271
  vol_spike = float(last_row['Vol_Spike'].iloc[0])
272
  rsi_9 = float(last_row['RSI_9'].iloc[0])
273
 
274
- # 🌊 V30: Flux Futures KuCoin
275
  futures_data = await fetch_kucoin_futures_data(symbol)
276
  oi, cvd = futures_data["oi"], futures_data["cvd"]
277
 
278
- # --- 🧠 CERVEAUX IA ---
279
  regime_scaled = regime_scaler.transform(last_row[["ATR_pct", "EMA200_slope", "Drawdown", "RSI_Macro"]])
280
  regime_pred = int(regime_model.predict(regime_scaled)[0])
281
 
282
  ml_cols = ["RSI", "Dist_High_24h", "Dist_Low_24h", "EMA_dist", "EMA_slope", "ATR_ratio", "VOL_ratio"]
283
  ml_prob = float(ml_model.predict_proba(last_row[ml_cols])[0][1])
284
-
285
  time_cols = ['return_1h', 'return_3h', 'return_12h', 'RSI_lag1', 'RSI_lag2', 'vol_lag1', 'VOL_RATIO']
286
  time_prob = float(time_model.predict_proba(last_row[time_cols])[0][1])
287
 
288
- # 🦖 DINO LightGBM (ou Fallback)
289
  dino_prob = 0.5
290
  if dino_brain:
291
  try: dino_prob = float(dino_brain.predict(last_row[ml_cols].values)[0])
@@ -293,10 +297,9 @@ async def predict_signal(symbol, timeframe="1h"):
293
 
294
  p_sent = await get_crypto_sentiment(symbol)
295
 
296
- # NOUVEAU CODE V30
297
  final_p, wt, wm, wl, ws = combine_scores(symbol, timeframe, time_prob, ml_prob, dino_prob, p_sent, regime_pred)
298
 
299
- # --- 🐋 SMART MONEY & CVD BOOST ---
300
  smc_status = "AUCUN"
301
  if int(last_row["Sweep_Low"].iloc[0]) == 1 and cvd > 0:
302
  final_p = min(0.95, final_p + 0.20)
@@ -309,11 +312,9 @@ async def predict_signal(symbol, timeframe="1h"):
309
  if final_p > 0.5 and vol_spike > 1.5 and rsi_9 < 70: final_p = min(0.95, final_p + 0.10)
310
  elif final_p < 0.5 and vol_spike > 1.5 and rsi_9 > 30: final_p = max(0.05, final_p - 0.10)
311
 
312
- # --- 🛡️ ADN DE LA BASE DE DONNÉES ---
313
  with sqlite3.connect(DB_NAME) as conn:
314
  res = conn.execute("SELECT tp_mult, sl_mult, min_prob, min_tp_dist FROM agent_logic WHERE symbol = ? AND timeframe = ?", (symbol, timeframe)).fetchone()
315
- if res:
316
- tp_m, sl_m, agent_min_prob, agent_min_tp_dist = res
317
  else:
318
  res_fallback = conn.execute("SELECT tp_mult, sl_mult, min_prob, min_tp_dist FROM agent_logic WHERE symbol = 'ALL' AND timeframe = ?", (timeframe,)).fetchone()
319
  tp_m, sl_m, agent_min_prob, agent_min_tp_dist = res_fallback if res_fallback else (1.5, 1.0, 0.55, 0.002)
@@ -327,7 +328,6 @@ async def predict_signal(symbol, timeframe="1h"):
327
  conf_val = max(0, min(1, 1 - np.std([time_prob, ml_prob, dino_prob, p_sent])))
328
  composite_score = max(0, min(100, (strength * 45) + (conf_val * 40) + (15 if regime_pred in [0, 1] else 5)))
329
 
330
- # 🛑 VETO DYNAMIQUE
331
  veto, veto_reason = False, ""
332
  dist_tp_pct = abs(tp - prix) / prix
333
  dist_fib = float(last_row["Dist_Fib_618"].iloc[0])
@@ -341,11 +341,10 @@ async def predict_signal(symbol, timeframe="1h"):
341
  elif final_p > 0.5 and dist_fib < -0.03: veto, veto_reason = True, "Support Fib 61.8 trop loin"
342
  elif final_p < 0.5 and dist_fib > 0.03: veto, veto_reason = True, "Résistance Fib 61.8 trop loin"
343
  elif dist_tp_pct < agent_min_tp_dist: veto, veto_reason = True, "Gain potentiel trop faible"
344
- elif final_p < 0.5 and (prix > ema200_val or prix > vwap): veto, veto_reason = True, "Short Interdit 🚫 (> EMA200/VWAP)"
345
- elif final_p > 0.5 and (prix < ema200_val or prix < vwap): veto, veto_reason = True, "Long Interdit 🚫 (< EMA200/VWAP)"
346
 
347
  if veto:
348
- print(f"🛑 [VETO] {symbol}: {veto_reason}")
349
  return {"symbol": symbol, "timeframe": timeframe, "status": "veto", "message": veto_reason, "price": prix, "final_score": round(final_p, 4)}
350
 
351
  db_task = (datetime.now(timezone.utc).isoformat(), symbol, timeframe, 'HAUSSIER' if final_p > 0.5 else 'BAISSIER', final_p, prix, tp, sl, 'EN_COURS', regime_pred, time_prob, ml_prob, dino_prob, p_sent, prix)
@@ -357,23 +356,7 @@ async def predict_signal(symbol, timeframe="1h"):
357
  }
358
  except Exception as e: return {"status": "error", "message": str(e)}
359
 
360
- # --- 🛡️ STATE MANAGER : LE DICTIONNAIRE D'ÉTAT GLOBAL ---
361
- # Clé : (symbol, timeframe) -> Valeur : Les données du dernier signal
362
- active_signals_state = {}
363
-
364
- def clean_old_db_signals(symbol, timeframe):
365
- """Passe les anciens signaux non résolus en statut REMPLACÉ pour laisser la place aux nouveaux."""
366
- try:
367
- with sqlite3.connect(DB_NAME) as conn:
368
- conn.execute(
369
- "UPDATE signals SET status = 'REMPLACÉ ♻️', confirmed = 0 "
370
- "WHERE symbol = ? AND timeframe = ? AND status = 'EN_COURS'",
371
- (symbol, timeframe)
372
- )
373
- conn.commit()
374
- except Exception as e:
375
- print(f"⚠️ Erreur nettoyage DB : {e}")
376
- # --- 🧬 FONCTION D'ÉVOLUTION (MUTATION) ---
377
  def mutate_agent(symbol, timeframe, success=True):
378
  try:
379
  with sqlite3.connect(DB_NAME) as conn:
@@ -382,136 +365,82 @@ def mutate_agent(symbol, timeframe, success=True):
382
  if not row: return
383
 
384
  tp, sl, prob = row['tp_mult'], row['sl_mult'], row['min_prob']
385
- if success:
386
- new_tp, new_sl, new_prob = tp * random.uniform(1.01, 1.05), sl * random.uniform(0.98, 1.00), max(0.60, prob - 0.01)
387
- else:
388
- new_tp, new_sl, new_prob = tp * random.uniform(0.90, 0.98), sl * random.uniform(1.02, 1.10), min(0.85, prob + 0.02)
389
 
390
  conn.execute('''UPDATE agent_logic SET tp_mult = ?, sl_mult = ?, min_prob = ?, generation = generation + 1 WHERE symbol = ? AND timeframe = ?''', (new_tp, new_sl, new_prob, symbol, timeframe))
391
- backup_db_to_hf()
 
 
392
  except Exception as e: print(f"🧬 Erreur Mutation : {e}")
393
 
394
- # --- 🧠 TRAINING ENGINE ---
395
  # --- 🧠 TRAINING ENGINE ---
396
  def trigger_training(symbol="BTC/USD"):
397
  try:
398
- print(f"⚙️ Tentative d'entraînement pour {symbol}...")
399
  memory_guard()
400
  bars = exchange_sync.fetch_ohlcv(symbol, timeframe='1h', limit=1500)
401
  df = pd.DataFrame(bars, columns=['ts', 'open', 'high', 'low', 'close', 'vol'])
402
  if len(df) < 500: return f"❌ Historique insuffisant."
403
 
404
  df_final = prepare_features_sync(symbol, '1h', limit_bars=1000)
405
- if df_final.empty or len(df_final) < 100: return f"❌ Données vides après indicateurs."
406
 
407
- # 1. Entraînement des vieux modèles (Fallback de sécurité)
408
- try:
409
- from ml_model import train_model as train_ml
410
- from time_model import train_time_model as train_time
411
- train_ml(df_final); train_time(df_final)
412
- except Exception as e: print(f"⚠️ Erreur Classique: {e}")
413
-
414
- # 2. 🦖 ENTRAÎNEMENT DU DINOSAURE (LightGBM)
415
  if LGBM_AVAILABLE:
416
- print("🦖 [V30] Forgeage du Cerveau LightGBM en cours...")
417
  ml_cols = ["RSI", "Dist_High_24h", "Dist_Low_24h", "EMA_dist", "EMA_slope", "ATR_ratio", "VOL_ratio"]
418
-
419
- # On crée la cible (la prochaine bougie sera-t-elle verte ?)
420
  df_final['Target'] = (df_final['close'].shift(-1) > df_final['close']).astype(int)
421
  df_train = df_final.dropna(subset=ml_cols + ['Target'])
422
-
423
- X = df_train[ml_cols]
424
- y = df_train['Target']
425
-
426
- params = {
427
- 'objective': 'binary',
428
- 'metric': 'binary_logloss',
429
- 'boosting_type': 'gbdt',
430
- 'learning_rate': 0.05,
431
- 'num_leaves': 31,
432
- 'verbose': -1
433
- }
434
- dtrain = lgb.Dataset(X, label=y)
435
-
436
- # Entraînement ultra-rapide
437
- model = lgb.train(params, dtrain, 100)
438
  model.save_model('dino_lgbm_model.txt')
439
-
440
  global dino_brain
441
  dino_brain = lgb.Booster(model_file='dino_lgbm_model.txt')
442
- print("✅ [V30] Cerveau LightGBM créé, sauvegardé et injecté !")
443
 
444
- # Rechargement des vieux modèles en mémoire globale
445
  global ml_model, time_model
446
  ml_model, time_model = joblib.load("ml_model_v9.pkl"), joblib.load("time_model.pkl")
447
  gc.collect()
448
-
449
- return f"✅ IA ré-entraînée avec succès (T-Rex en ligne !)."
450
- except Exception as e:
451
- return f"❌ Erreur Training : {e}"
452
 
453
- # --- 🚀 MOTEUR AUTO-PILOTE & DREAM MODE ---
454
  AUTO_SYMBOLS = ["BTC/USD", "ETH/USD"]
455
  AUTO_TIMEFRAMES = ["1m", "5m", "15m", "1h"]
456
 
457
  def set_bot_mode(mode):
458
  global DREAM_MODE_ACTIVE
459
  target_mode = mode[0] if isinstance(mode, list) else str(mode)
460
- if "LIVE" in target_mode.upper():
461
- DREAM_MODE_ACTIVE = False
462
- msg = "🛰️ Mode LIVE activé : Le cerveau est en alerte."
463
- else:
464
- DREAM_MODE_ACTIVE = True
465
- msg = "🌙 Mode DREAM activé : Début du Backtest Évolutif."
466
- print(f"[SYSTEM] {msg}")
467
  return {"status": "success", "mode": "DREAM" if DREAM_MODE_ACTIVE else "LIVE", "message": msg}
468
 
469
- async def auto_predict_loop():
470
- print("👁️ [SCANNER] Le Cerveau Global est en ligne (H24)...")
471
  while True:
472
  for symbol in AUTO_SYMBOLS:
473
  for tf in AUTO_TIMEFRAMES:
474
  try:
475
- # 1️⃣ L'IA RÉFLÉCHIT EN CONTINU (Aucun blocage)
476
  pred = await predict_signal(symbol, timeframe=tf)
477
-
478
  if pred and pred.get("status") == "success":
479
- # 2️⃣ NETTOYAGE DB : On archive l'ancien signal avant d'enregistrer le nouveau
480
  clean_old_db_signals(symbol, tf)
481
-
482
- # 3️⃣ ÉCRASEMENT MATHÉMATIQUE : Le nouveau signal tue l'ancien instantanément en RAM
483
  active_signals_state[(symbol, tf)] = pred
484
-
485
- # 4️⃣ ACTION : C'est ici que le mode intervient !
486
  if not DREAM_MODE_ACTIVE:
487
- print(f"🎯 [LIVE] Nouveau signal maître pris en compte : {symbol} [{tf}]")
488
- # C'est ici que tu déclencheras l'API KuCoin/MT5 pour prendre le trade
489
- else:
490
- # En mode DREAM, on log juste ou on laisse le backtest tourner
491
- pass
492
-
493
- await asyncio.sleep(5) # Sécurité anti-spam API KuCoin
494
- except Exception as e:
495
- print(f"⚠️ Erreur Scanner sur {symbol} [{tf}] : {e}")
496
-
497
- await asyncio.sleep(60) # Pause entre deux scans complets du marché
498
 
499
  async def dream_simulation_loop():
500
- """Le Spinosaurus rêve sur TOUS les terrains (Multi-Timeframe)"""
501
  while True:
502
  if DREAM_MODE_ACTIVE:
503
- print("🌙 [DREAM] Début de la session de backtest multi-timeframe...")
504
  for symbol in AUTO_SYMBOLS:
505
- for tf in AUTO_TIMEFRAMES: # ⚡ LA BOUCLE MAGIQUE EST LÀ !
506
  try:
507
- # On utilise 'tf' au lieu de "1m"
508
  df = prepare_features_sync(symbol, timeframe=tf, limit_bars=200)
509
  if df.empty or len(df) < 50: continue
510
 
511
  idx = random.randint(10, len(df) - 30)
512
- test_row = df.iloc[[idx]]
513
-
514
- pred = await predict_signal(symbol, timeframe=tf) # ⚡ 'tf' ici aussi
515
  if pred.get("status") == "success":
516
  future_data = df.iloc[idx+1 : idx+25]
517
  win = False
@@ -522,36 +451,29 @@ async def dream_simulation_loop():
522
  else:
523
  if row['low'] <= pred['tp']: win = True; break
524
  if row['high'] >= pred['sl']: win = False; break
525
-
526
- mutate_agent(symbol, tf, success=win) # ⚡ Et 'tf' ici !
527
- print(f"🧬 [DREAM] Mutation [{tf}] sur {symbol} : {'✅ GAGNANTE' if win else '❌ PERDANTE'}")
528
-
529
- await asyncio.sleep(3) # 🛡️ Sécurité anti-ban KuCoin
530
- except Exception as e:
531
- print(f"⚠️ Erreur DREAM sur {symbol} [{tf}]: {e}")
532
-
533
  await asyncio.sleep(60)
534
 
535
- # --- ⚖️ TOOLS (API EXNESS & DB) ---
536
  def keep_alive_ping(): return {"status": "awake", "time": datetime.now(timezone.utc).isoformat()}
537
  def confirm_trade_api(trade_id, real_price):
538
  try:
539
- t_id, r_price = int(trade_id), float(real_price)
540
  with sqlite3.connect(DB_NAME) as conn:
541
  conn.row_factory, cursor = sqlite3.Row, conn.cursor()
542
- cursor.execute("SELECT price, tp, sl FROM signals WHERE id = ?", (t_id,))
543
  t = cursor.fetchone()
544
  if not t: return {"status": "error"}
545
- ecart = r_price - t['price']
546
- cursor.execute("UPDATE signals SET confirmed = 1, price = ?, tp = ?, sl = ?, peak_price = ? WHERE id = ?", (r_price, t['tp'] + ecart, t['sl'] + ecart, r_price, t_id))
547
  conn.commit()
548
  return {"status": "success"}
549
- except Exception as e: return {"status": "error"}
 
550
  def cancel_trade_api(trade_id):
551
  try:
552
- with sqlite3.connect(DB_NAME) as conn:
553
- conn.execute("UPDATE signals SET status = 'ANNULÉ 🗑️', confirmed = 0 WHERE id = ?", (int(trade_id),))
554
- conn.commit()
555
  return {"status": "success"}
556
  except: return {"status": "error"}
557
 
@@ -577,8 +499,6 @@ def run_judge_api():
577
  current_price = exchange_sync.fetch_ticker(f_sym)['last']
578
 
579
  diff = (t['price'] - current_price) if t['direction'] == 'BAISSIER' else (current_price - t['price'])
580
- pnl_live = diff * 0.1 * 10
581
-
582
  sl_dyn, peak = t['sl'], t['peak_price']
583
  new_peak = max(peak, current_price) if t['direction'] == 'HAUSSIER' else min(peak, current_price)
584
  progression = abs(current_price - t['price']) / abs(t['tp'] - t['price']) if abs(t['tp'] - t['price']) > 0 else 0
@@ -587,11 +507,9 @@ def run_judge_api():
587
  if t['direction'] == 'HAUSSIER':
588
  if progression >= 0.75: nouveau_sl = max(sl_dyn, t['price'] + (abs(t['tp'] - t['price']) * 0.60))
589
  elif progression >= 0.50: nouveau_sl = max(sl_dyn, t['price'] + (abs(t['tp'] - t['price']) * 0.25))
590
- elif progression >= 0.25: nouveau_sl = max(sl_dyn, t['price'] + (abs(t['tp'] - t['price']) * 0.05))
591
  else:
592
  if progression >= 0.75: nouveau_sl = min(sl_dyn, t['price'] - (abs(t['tp'] - t['price']) * 0.60))
593
  elif progression >= 0.50: nouveau_sl = min(sl_dyn, t['price'] - (abs(t['tp'] - t['price']) * 0.25))
594
- elif progression >= 0.25: nouveau_sl = min(sl_dyn, t['price'] - (abs(t['tp'] - t['price']) * 0.05))
595
 
596
  cursor.execute("UPDATE signals SET peak_price = ?, sl = ? WHERE id = ?", (new_peak, nouveau_sl, t['id']))
597
  outcome, reward = None, 0
@@ -603,139 +521,66 @@ def run_judge_api():
603
  elif current_price >= nouveau_sl: outcome, reward = ("GAGNÉ (PARTIEL) 💸", 1) if nouveau_sl < t['price'] else ("PERDU ❌", -5)
604
 
605
  if outcome:
606
- pnl_dollars = (((abs(current_price - t['price'])) / t['price']) * 1000.0) - 0.25
607
- if outcome == "SL TOUCHÉ 🛡️" and pnl_dollars < 0: outcome = "TUÉ PAR LE SPREAD 🩸"
608
- elif outcome == "GAGNÉ (PARTIEL) 💸" and pnl_dollars <= 0: outcome = "FAUX GAIN 📉"
609
-
610
- # 🧬 MUTATION RÉELLE V30
611
- is_win = reward > 0
612
- mutate_agent(t['symbol'], t['timeframe'], success=is_win)
613
  cursor.execute("UPDATE signals SET status=? WHERE id=?", (outcome, t['id']))
614
  closed_trades.append({"symbol": t['symbol'], "id": t['id']})
615
- except Exception as inner_e: print(f"⚠️ Erreur Juge: {inner_e}")
616
  conn.commit()
617
- if closed_trades: return {"status": "updates", "data": closed_trades}
618
- return {"status": "waiting"}
619
  except Exception as e: return {"status": "error", "message": str(e)}
620
 
621
- def training_wrapper(symbol, *args):
622
- s = "BTC/USD" if not isinstance(symbol, str) or len(str(symbol)) < 2 else str(symbol).strip().upper()
623
- return trigger_training(s)
624
-
625
  def get_bot_skills():
626
  try:
627
  with sqlite3.connect(DB_NAME) as conn:
628
- cursor = conn.cursor()
629
- cursor.execute("SELECT symbol, timeframe, tp_mult, sl_mult, min_prob, generation FROM agent_logic ORDER BY symbol, timeframe")
630
- return [[r[0], r[1], f"x{round(r[2], 2)}", f"x{round(r[3], 2)}", f"{round(r[4]*100)}%", f"🧬 Gen {r[5]}"] for r in cursor.fetchall()]
631
  except Exception as e: return [[f"Erreur: {str(e)}", "-", "-", "-", "-", "-"]]
632
-
633
  def force_scalping_mode():
634
  try:
635
- with sqlite3.connect(DB_NAME) as conn:
636
- conn.execute("UPDATE agent_logic SET tp_mult = 1.8")
637
- conn.commit()
638
  return get_bot_skills()
639
  except: return [["Erreur", "-", "-", "-", "-", "-"]]
640
-
641
  def get_active_signals():
642
  try:
643
- conn = sqlite3.connect(DB_NAME, timeout=10)
644
- conn.row_factory = sqlite3.Row
645
- trades = [dict(row) for row in conn.cursor().execute("SELECT * FROM signals WHERE status = 'EN_COURS'").fetchall()]
646
- conn.close()
647
- return trades
648
  except: return []
649
 
650
- def backup_db_to_hf():
651
- """Sauvegarde la DB sur Hugging Face pour survivre aux reboots."""
652
- if not HF_TOKEN:
653
- print("⚠️ HF_TOKEN manquant, backup impossible.")
654
- return
655
-
656
- try:
657
- api = HfApi()
658
- # Remplace par ton vrai nom d'utilisateur et le nom d'un dataset privé que tu as créé
659
- repo_id = "Nexo-S/AlphaTrade-DB"
660
- api.upload_file(
661
- path_or_fileobj=DB_NAME,
662
- path_in_repo=DB_NAME,
663
- repo_id=repo_id,
664
- repo_type="dataset",
665
- token=HF_TOKEN
666
- )
667
- print("☁️ [BACKUP] Base de données sauvegardée sur Hugging Face !")
668
- except Exception as e:
669
- print(f"❌ Erreur Backup HF : {e}")
670
-
671
- def restore_db_from_hf():
672
- """Récupère le dernier ADN du bot depuis HF au démarrage du Space."""
673
- if not HF_TOKEN:
674
- print("⚠️ HF_TOKEN manquant, restauration impossible.")
675
- return
676
-
677
- try:
678
- print("🔄 [SYSTEM] Tentative de récupération de l'ADN depuis Hugging Face...")
679
- file_path = hf_hub_download(
680
- repo_id="Nexo-S/AlphaTrade-DB",
681
- filename=DB_NAME,
682
- repo_type="dataset",
683
- token=HF_TOKEN
684
- )
685
- shutil.copy(file_path, DB_NAME)
686
- print("✅ [RESTORE] Base de données (ADN) récupérée avec succès !")
687
- except Exception as e:
688
- print(f"⚠️ Aucun backup trouvé ou erreur (C'est normal si c'est le 1er lancement) : {e}")
689
-
690
  # --- 🎨 INTERFACE GRADIO V30 ---
691
  with gr.Blocks(theme=gr.themes.Monochrome()) as iface:
692
- gr.Markdown("# 🦖 Alpha V30 Dinosaur Engine")
693
-
694
- with gr.Tab("Admin"):
695
- admin_sym = gr.Textbox(label="Symbole à recalibrer", value="BTC/USDT")
696
- gr.Button("Forcer Entraînement", variant="stop").click(fn=training_wrapper, inputs=admin_sym, outputs=gr.Textbox(), api_name="trigger_training")
697
-
698
- with gr.Tab("🎯 Prédictions"):
699
- btn_pred = gr.Button("Predict", variant="primary")
700
- btn_pred.click(fn=predict_signal, inputs=[gr.Textbox(label="Symbole", value="BTC/USD"), gr.Dropdown(choices=["1m", "5m", "15m", "1h"], value="1h")], outputs=gr.JSON())
701
-
702
  with gr.Tab("⚖️ Système"):
703
  gr.Button("Judge").click(fn=run_judge_api, outputs=gr.JSON(), api_name="run_judge_api")
704
  gr.Button("Get Active", visible=False).click(fn=get_active_signals, outputs=gr.JSON(), api_name="get_active_signals")
705
  gr.Button("Ping", visible=False).click(fn=keep_alive_ping, outputs=gr.JSON(), api_name="keep_alive_ping")
706
  gr.Button("Set Mode", visible=False).click(fn=set_bot_mode, inputs=gr.Textbox(visible=False), outputs=gr.JSON(), api_name="set_bot_mode")
707
-
708
  with gr.Tab("📊 Stats (ADN)"):
709
  skills_table = gr.Dataframe(headers=["Marché", "Timeframe", "Cible (TP)", "Risque (SL)", "Peur Min.", "Génération"], value=get_bot_skills(), interactive=False)
710
  with gr.Row():
711
  gr.Button("🔄 Actualiser").click(get_bot_skills, outputs=skills_table)
712
  gr.Button("⚡ Mode Scalping Force").click(force_scalping_mode, outputs=skills_table)
713
-
714
  gr.Button(visible=False).click(fn=confirm_trade_api, inputs=[gr.Textbox(visible=False), gr.Textbox(visible=False)], outputs=gr.JSON(), api_name="confirm_trade_api")
715
  gr.Button(visible=False).click(fn=cancel_trade_api, inputs=gr.Textbox(visible=False), outputs=gr.JSON(), api_name="cancel_trade_api")
716
  iface.load(get_bot_skills, outputs=skills_table)
717
 
718
  import threading
719
  _auto_pilot_started = False
720
-
721
  def run_auto_pilot():
722
  global _auto_pilot_started
723
  if _auto_pilot_started: return
724
  _auto_pilot_started = True
725
- print("⏳ [SYSTEM] Attente 30s avant propulsion V30...")
726
- time.sleep(30)
727
  try:
728
  loop = asyncio.new_event_loop()
729
  asyncio.set_event_loop(loop)
730
-
731
- # Le Cerveau (H24) + Le Rêve (Mutations) tournent en parallèle
732
- loop.create_task(auto_predict_loop())
733
  loop.create_task(dream_simulation_loop())
734
  loop.run_forever()
735
- except Exception as e:
736
- print(f"⚠️ Erreur boucle Auto-Pilote : {e}")
737
- _auto_pilot_started = False
738
- _auto_pilot_started = False
739
 
740
  if __name__ == "__main__":
741
  try: threading.Thread(target=run_auto_pilot, daemon=True).start()
 
1
+ # --- 🏴‍☠️ MONKEY PATCH & IMPORTS ---
2
  import huggingface_hub
3
  try:
4
  from huggingface_hub import HfFolder
 
24
  from types import ModuleType
25
  import yfinance as yf
26
 
27
+ # --- 🦖 IMPORT LIGHTGBM ---
28
  try:
29
  import lightgbm as lgb
30
  LGBM_AVAILABLE = True
31
  except ImportError:
32
  LGBM_AVAILABLE = False
33
+ print("⚠️ LightGBM non installé.")
34
 
35
  try:
36
  import MetaTrader5 as mt5
37
  MT5_AVAILABLE = True
38
  except ImportError:
39
  MT5_AVAILABLE = False
40
+ print("🌐 [CLOUD MODE] MetaTrader5 non détecté.")
41
 
42
  # --- 🥷 NINJA HACK : MOCK PANDAS_TA ---
43
  if "pandas_ta" not in sys.modules:
44
  mock_ta = ModuleType("pandas_ta")
45
  sys.modules["pandas_ta"] = mock_ta
 
 
46
  if not hasattr(pd.DataFrame, "ta"):
47
  class FakeTA:
48
  def __getattr__(self, name): return lambda *args, **kwargs: None
 
73
 
74
  market_cache, last_fetch_time = {}, {}
75
  CACHE_DURATION = 300
76
+ DREAM_MODE_ACTIVE = True
77
 
78
  try:
79
  from sentiment_engine import get_crypto_sentiment
 
80
  except:
81
  async def get_crypto_sentiment(symbol): return 0.5
82
  try:
83
  from ensemble import combine_scores
84
  except:
85
+ def combine_scores(symbol, timeframe, t, m, l, sent, r): return (t+m+l+sent)/4, 0.25, 0.25, 0.25, 0.25
86
 
87
+ # --- DB, SYNC & HUGGING FACE BACKUP ---
88
+ DB_NAME = "alphatrade_v30_dino.db"
89
  HF_TOKEN = os.environ.get("HF_TOKEN")
90
+ HF_REPO_ID = "Nexo-S/AlphaTrade-DB"
91
+
92
+ def restore_db_from_hf():
93
+ if not HF_TOKEN: return
94
+ try:
95
+ print("🔄 [SYSTEM] Restauration ADN depuis HF...")
96
+ file_path = hf_hub_download(repo_id=HF_REPO_ID, filename=DB_NAME, repo_type="dataset", token=HF_TOKEN)
97
+ shutil.copy(file_path, DB_NAME)
98
+ print("✅ [RESTORE] ADN récupéré !")
99
+ except Exception as e: print(f"⚠️ Aucun backup trouvé (1er lancement) : {e}")
100
+
101
+ def backup_db_to_hf():
102
+ if not HF_TOKEN: return
103
+ try:
104
+ api = HfApi()
105
+ api.upload_file(path_or_fileobj=DB_NAME, path_in_repo=DB_NAME, repo_id=HF_REPO_ID, repo_type="dataset", token=HF_TOKEN)
106
+ print("☁️ [BACKUP] ADN sauvegardé sur Hugging Face !")
107
+ except Exception as e: print(f"❌ Erreur Backup HF : {e}")
108
 
109
  def init_db():
110
  try:
 
118
 
119
  cursor = conn.cursor()
120
  cursor.execute("PRAGMA table_info(agent_logic)")
121
+ if not [col[1] for col in cursor.fetchall()]:
 
 
122
  conn.execute('''CREATE TABLE IF NOT EXISTS agent_logic (
123
  symbol TEXT, timeframe TEXT, tp_mult REAL, sl_mult REAL,
124
  score REAL, last_pnl REAL, min_prob REAL, min_tp_dist REAL,
 
135
  ('ALL', '4h', 3.0, 2.0, 0, 0, 0.50, 0.008, 1, 0, 0)
136
  ]
137
  conn.executemany("INSERT INTO agent_logic VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", defaults)
138
+ except Exception as e: print(f"❌ Erreur DB: {e}")
 
139
 
140
  async def save_to_db(data):
141
  try:
 
144
  conn.commit()
145
  except Exception as e: print(f"❌ DB Error : {e}")
146
 
147
+ # 🚀 INITIALISATION
148
+ restore_db_from_hf()
149
+ init_db()
150
+
151
+ # --- 🛡️ STATE MANAGER ---
152
+ active_signals_state = {}
153
+
154
+ def clean_old_db_signals(symbol, timeframe):
155
+ try:
156
+ with sqlite3.connect(DB_NAME) as conn:
157
+ conn.execute("UPDATE signals SET status = 'REMPLACÉ ♻️', confirmed = 0 WHERE symbol = ? AND timeframe = ? AND status = 'EN_COURS'", (symbol, timeframe))
158
+ conn.commit()
159
+ except Exception as e: print(f"⚠️ Erreur nettoyage DB : {e}")
160
 
161
  def memory_guard():
162
  if psutil.virtual_memory().percent > 80:
 
186
  time_model = joblib.load("time_model.pkl")
187
  regime_model = joblib.load("regime_model.pkl")
188
  regime_scaler = joblib.load("regime_scaler.pkl")
 
189
  except Exception as e: print(f"⚠️ Erreur IA Classique : {e}")
190
 
191
  try:
192
  dino_brain = lgb.Booster(model_file='dino_lgbm_model.txt') if LGBM_AVAILABLE else None
 
193
  except:
194
  dino_brain = None
 
195
 
196
  # --- 📊 FEATURES ENGINE ---
197
  async def fetch_kucoin_futures_data(symbol):
 
198
  try:
199
  ku_sym = symbol.replace("/", "").replace("BTC", "XBT") + "M"
200
  async with aiohttp.ClientSession() as session:
 
202
  trade_url = f"https://api-futures.kucoin.com/api/v1/trade/history?symbol={ku_sym}"
203
  async with session.get(oi_url) as r1, session.get(trade_url) as r2:
204
  oi_json = await r1.json()
205
+ trades = (await r2.json()).get("data", [])
 
206
  cvd = sum([float(t.get("size", 0)) if t.get("side") == "buy" else -float(t.get("size", 0)) for t in trades])
207
  return {"oi": float(oi_json.get("data", {}).get("value", 0)), "cvd": cvd}
208
  except: return {"oi": 0, "cvd": 0}
 
215
  if cache_key in market_cache and now - last_fetch_time.get(cache_key, 0) < CACHE_DURATION:
216
  df = market_cache[cache_key].copy()
217
  else:
218
+ fetch_symbol = symbol if "/USDT" in symbol else symbol.replace("/USD", "/USDT")
219
+ if "/" not in fetch_symbol: fetch_symbol += "/USDT"
220
+
221
+ df = pd.DataFrame()
222
+ for attempt in range(3):
223
+ try:
224
+ bars = exchange_sync.fetch_ohlcv(fetch_symbol, timeframe, limit=limit_bars)
225
+ df = pd.DataFrame(bars, columns=['ts', 'open', 'high', 'low', 'close', 'vol'])
226
+ if not df.empty: break
227
+ except: time.sleep(2)
 
 
 
 
 
 
 
 
 
228
 
229
  if df.empty: return pd.DataFrame()
230
  market_cache[cache_key], last_fetch_time[cache_key] = df.copy(), now
 
279
  vol_spike = float(last_row['Vol_Spike'].iloc[0])
280
  rsi_9 = float(last_row['RSI_9'].iloc[0])
281
 
 
282
  futures_data = await fetch_kucoin_futures_data(symbol)
283
  oi, cvd = futures_data["oi"], futures_data["cvd"]
284
 
 
285
  regime_scaled = regime_scaler.transform(last_row[["ATR_pct", "EMA200_slope", "Drawdown", "RSI_Macro"]])
286
  regime_pred = int(regime_model.predict(regime_scaled)[0])
287
 
288
  ml_cols = ["RSI", "Dist_High_24h", "Dist_Low_24h", "EMA_dist", "EMA_slope", "ATR_ratio", "VOL_ratio"]
289
  ml_prob = float(ml_model.predict_proba(last_row[ml_cols])[0][1])
 
290
  time_cols = ['return_1h', 'return_3h', 'return_12h', 'RSI_lag1', 'RSI_lag2', 'vol_lag1', 'VOL_RATIO']
291
  time_prob = float(time_model.predict_proba(last_row[time_cols])[0][1])
292
 
 
293
  dino_prob = 0.5
294
  if dino_brain:
295
  try: dino_prob = float(dino_brain.predict(last_row[ml_cols].values)[0])
 
297
 
298
  p_sent = await get_crypto_sentiment(symbol)
299
 
300
+ # ENSEMBLE V30
301
  final_p, wt, wm, wl, ws = combine_scores(symbol, timeframe, time_prob, ml_prob, dino_prob, p_sent, regime_pred)
302
 
 
303
  smc_status = "AUCUN"
304
  if int(last_row["Sweep_Low"].iloc[0]) == 1 and cvd > 0:
305
  final_p = min(0.95, final_p + 0.20)
 
312
  if final_p > 0.5 and vol_spike > 1.5 and rsi_9 < 70: final_p = min(0.95, final_p + 0.10)
313
  elif final_p < 0.5 and vol_spike > 1.5 and rsi_9 > 30: final_p = max(0.05, final_p - 0.10)
314
 
 
315
  with sqlite3.connect(DB_NAME) as conn:
316
  res = conn.execute("SELECT tp_mult, sl_mult, min_prob, min_tp_dist FROM agent_logic WHERE symbol = ? AND timeframe = ?", (symbol, timeframe)).fetchone()
317
+ if res: tp_m, sl_m, agent_min_prob, agent_min_tp_dist = res
 
318
  else:
319
  res_fallback = conn.execute("SELECT tp_mult, sl_mult, min_prob, min_tp_dist FROM agent_logic WHERE symbol = 'ALL' AND timeframe = ?", (timeframe,)).fetchone()
320
  tp_m, sl_m, agent_min_prob, agent_min_tp_dist = res_fallback if res_fallback else (1.5, 1.0, 0.55, 0.002)
 
328
  conf_val = max(0, min(1, 1 - np.std([time_prob, ml_prob, dino_prob, p_sent])))
329
  composite_score = max(0, min(100, (strength * 45) + (conf_val * 40) + (15 if regime_pred in [0, 1] else 5)))
330
 
 
331
  veto, veto_reason = False, ""
332
  dist_tp_pct = abs(tp - prix) / prix
333
  dist_fib = float(last_row["Dist_Fib_618"].iloc[0])
 
341
  elif final_p > 0.5 and dist_fib < -0.03: veto, veto_reason = True, "Support Fib 61.8 trop loin"
342
  elif final_p < 0.5 and dist_fib > 0.03: veto, veto_reason = True, "Résistance Fib 61.8 trop loin"
343
  elif dist_tp_pct < agent_min_tp_dist: veto, veto_reason = True, "Gain potentiel trop faible"
344
+ elif final_p < 0.5 and (prix > ema200_val or prix > vwap): veto, veto_reason = True, "Short Interdit 🚫"
345
+ elif final_p > 0.5 and (prix < ema200_val or prix < vwap): veto, veto_reason = True, "Long Interdit 🚫"
346
 
347
  if veto:
 
348
  return {"symbol": symbol, "timeframe": timeframe, "status": "veto", "message": veto_reason, "price": prix, "final_score": round(final_p, 4)}
349
 
350
  db_task = (datetime.now(timezone.utc).isoformat(), symbol, timeframe, 'HAUSSIER' if final_p > 0.5 else 'BAISSIER', final_p, prix, tp, sl, 'EN_COURS', regime_pred, time_prob, ml_prob, dino_prob, p_sent, prix)
 
356
  }
357
  except Exception as e: return {"status": "error", "message": str(e)}
358
 
359
+ # --- 🧬 FONCTION D'ÉVOLUTION ---
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
360
  def mutate_agent(symbol, timeframe, success=True):
361
  try:
362
  with sqlite3.connect(DB_NAME) as conn:
 
365
  if not row: return
366
 
367
  tp, sl, prob = row['tp_mult'], row['sl_mult'], row['min_prob']
368
+ if success: new_tp, new_sl, new_prob = tp * random.uniform(1.01, 1.05), sl * random.uniform(0.98, 1.00), max(0.60, prob - 0.01)
369
+ else: new_tp, new_sl, new_prob = tp * random.uniform(0.90, 0.98), sl * random.uniform(1.02, 1.10), min(0.85, prob + 0.02)
 
 
370
 
371
  conn.execute('''UPDATE agent_logic SET tp_mult = ?, sl_mult = ?, min_prob = ?, generation = generation + 1 WHERE symbol = ? AND timeframe = ?''', (new_tp, new_sl, new_prob, symbol, timeframe))
372
+
373
+ # ☁️ SAUVEGARDE HF APRÈS MUTATION
374
+ backup_db_to_hf()
375
  except Exception as e: print(f"🧬 Erreur Mutation : {e}")
376
 
 
377
  # --- 🧠 TRAINING ENGINE ---
378
  def trigger_training(symbol="BTC/USD"):
379
  try:
 
380
  memory_guard()
381
  bars = exchange_sync.fetch_ohlcv(symbol, timeframe='1h', limit=1500)
382
  df = pd.DataFrame(bars, columns=['ts', 'open', 'high', 'low', 'close', 'vol'])
383
  if len(df) < 500: return f"❌ Historique insuffisant."
384
 
385
  df_final = prepare_features_sync(symbol, '1h', limit_bars=1000)
386
+ if df_final.empty or len(df_final) < 100: return f"❌ Données vides."
387
 
 
 
 
 
 
 
 
 
388
  if LGBM_AVAILABLE:
 
389
  ml_cols = ["RSI", "Dist_High_24h", "Dist_Low_24h", "EMA_dist", "EMA_slope", "ATR_ratio", "VOL_ratio"]
 
 
390
  df_final['Target'] = (df_final['close'].shift(-1) > df_final['close']).astype(int)
391
  df_train = df_final.dropna(subset=ml_cols + ['Target'])
392
+ X, y = df_train[ml_cols], df_train['Target']
393
+ params = {'objective': 'binary', 'metric': 'binary_logloss', 'boosting_type': 'gbdt', 'learning_rate': 0.05, 'num_leaves': 31, 'verbose': -1}
394
+ model = lgb.train(params, lgb.Dataset(X, label=y), 100)
 
 
 
 
 
 
 
 
 
 
 
 
 
395
  model.save_model('dino_lgbm_model.txt')
 
396
  global dino_brain
397
  dino_brain = lgb.Booster(model_file='dino_lgbm_model.txt')
 
398
 
 
399
  global ml_model, time_model
400
  ml_model, time_model = joblib.load("ml_model_v9.pkl"), joblib.load("time_model.pkl")
401
  gc.collect()
402
+ return f"✅ IA ré-entraînée."
403
+ except Exception as e: return f"❌ Erreur Training : {e}"
 
 
404
 
405
+ # --- 🚀 MOTEURS AUTO-PILOTE ---
406
  AUTO_SYMBOLS = ["BTC/USD", "ETH/USD"]
407
  AUTO_TIMEFRAMES = ["1m", "5m", "15m", "1h"]
408
 
409
  def set_bot_mode(mode):
410
  global DREAM_MODE_ACTIVE
411
  target_mode = mode[0] if isinstance(mode, list) else str(mode)
412
+ if "LIVE" in target_mode.upper(): DREAM_MODE_ACTIVE, msg = False, "🛰️ Mode LIVE activé"
413
+ else: DREAM_MODE_ACTIVE, msg = True, "🌙 Mode DREAM activé"
 
 
 
 
 
414
  return {"status": "success", "mode": "DREAM" if DREAM_MODE_ACTIVE else "LIVE", "message": msg}
415
 
416
+ async def universal_scanner_loop():
417
+ print("👁️ [SCANNER] Le Cerveau Global est en ligne H24...")
418
  while True:
419
  for symbol in AUTO_SYMBOLS:
420
  for tf in AUTO_TIMEFRAMES:
421
  try:
 
422
  pred = await predict_signal(symbol, timeframe=tf)
 
423
  if pred and pred.get("status") == "success":
 
424
  clean_old_db_signals(symbol, tf)
 
 
425
  active_signals_state[(symbol, tf)] = pred
426
+
 
427
  if not DREAM_MODE_ACTIVE:
428
+ print(f"🎯 [LIVE] Action requise pour {symbol} [{tf}] : Passage d'ordre.")
429
+ await asyncio.sleep(5)
430
+ except Exception as e: print(f"⚠️ Erreur Scanner {symbol} [{tf}]: {e}")
431
+ await asyncio.sleep(60)
 
 
 
 
 
 
 
432
 
433
  async def dream_simulation_loop():
 
434
  while True:
435
  if DREAM_MODE_ACTIVE:
 
436
  for symbol in AUTO_SYMBOLS:
437
+ for tf in AUTO_TIMEFRAMES:
438
  try:
 
439
  df = prepare_features_sync(symbol, timeframe=tf, limit_bars=200)
440
  if df.empty or len(df) < 50: continue
441
 
442
  idx = random.randint(10, len(df) - 30)
443
+ pred = await predict_signal(symbol, timeframe=tf)
 
 
444
  if pred.get("status") == "success":
445
  future_data = df.iloc[idx+1 : idx+25]
446
  win = False
 
451
  else:
452
  if row['low'] <= pred['tp']: win = True; break
453
  if row['high'] >= pred['sl']: win = False; break
454
+ mutate_agent(symbol, tf, success=win)
455
+ await asyncio.sleep(3)
456
+ except Exception: pass
 
 
 
 
 
457
  await asyncio.sleep(60)
458
 
459
+ # --- ⚖️ TOOLS ---
460
  def keep_alive_ping(): return {"status": "awake", "time": datetime.now(timezone.utc).isoformat()}
461
  def confirm_trade_api(trade_id, real_price):
462
  try:
 
463
  with sqlite3.connect(DB_NAME) as conn:
464
  conn.row_factory, cursor = sqlite3.Row, conn.cursor()
465
+ cursor.execute("SELECT price, tp, sl FROM signals WHERE id = ?", (int(trade_id),))
466
  t = cursor.fetchone()
467
  if not t: return {"status": "error"}
468
+ ecart = float(real_price) - t['price']
469
+ cursor.execute("UPDATE signals SET confirmed = 1, price = ?, tp = ?, sl = ?, peak_price = ? WHERE id = ?", (float(real_price), t['tp'] + ecart, t['sl'] + ecart, float(real_price), int(trade_id)))
470
  conn.commit()
471
  return {"status": "success"}
472
+ except: return {"status": "error"}
473
+
474
  def cancel_trade_api(trade_id):
475
  try:
476
+ with sqlite3.connect(DB_NAME) as conn: conn.execute("UPDATE signals SET status = 'ANNULÉ 🗑️', confirmed = 0 WHERE id = ?", (int(trade_id),)); conn.commit()
 
 
477
  return {"status": "success"}
478
  except: return {"status": "error"}
479
 
 
499
  current_price = exchange_sync.fetch_ticker(f_sym)['last']
500
 
501
  diff = (t['price'] - current_price) if t['direction'] == 'BAISSIER' else (current_price - t['price'])
 
 
502
  sl_dyn, peak = t['sl'], t['peak_price']
503
  new_peak = max(peak, current_price) if t['direction'] == 'HAUSSIER' else min(peak, current_price)
504
  progression = abs(current_price - t['price']) / abs(t['tp'] - t['price']) if abs(t['tp'] - t['price']) > 0 else 0
 
507
  if t['direction'] == 'HAUSSIER':
508
  if progression >= 0.75: nouveau_sl = max(sl_dyn, t['price'] + (abs(t['tp'] - t['price']) * 0.60))
509
  elif progression >= 0.50: nouveau_sl = max(sl_dyn, t['price'] + (abs(t['tp'] - t['price']) * 0.25))
 
510
  else:
511
  if progression >= 0.75: nouveau_sl = min(sl_dyn, t['price'] - (abs(t['tp'] - t['price']) * 0.60))
512
  elif progression >= 0.50: nouveau_sl = min(sl_dyn, t['price'] - (abs(t['tp'] - t['price']) * 0.25))
 
513
 
514
  cursor.execute("UPDATE signals SET peak_price = ?, sl = ? WHERE id = ?", (new_peak, nouveau_sl, t['id']))
515
  outcome, reward = None, 0
 
521
  elif current_price >= nouveau_sl: outcome, reward = ("GAGNÉ (PARTIEL) 💸", 1) if nouveau_sl < t['price'] else ("PERDU ❌", -5)
522
 
523
  if outcome:
524
+ mutate_agent(t['symbol'], t['timeframe'], success=(reward>0))
 
 
 
 
 
 
525
  cursor.execute("UPDATE signals SET status=? WHERE id=?", (outcome, t['id']))
526
  closed_trades.append({"symbol": t['symbol'], "id": t['id']})
527
+ except: pass
528
  conn.commit()
529
+ return {"status": "updates", "data": closed_trades} if closed_trades else {"status": "waiting"}
 
530
  except Exception as e: return {"status": "error", "message": str(e)}
531
 
532
+ def training_wrapper(symbol, *args): return trigger_training(str(symbol).strip().upper() if isinstance(symbol, str) else "BTC/USD")
 
 
 
533
  def get_bot_skills():
534
  try:
535
  with sqlite3.connect(DB_NAME) as conn:
536
+ return [[r[0], r[1], f"x{round(r[2], 2)}", f"x{round(r[3], 2)}", f"{round(r[4]*100)}%", f"🧬 Gen {r[5]}"] for r in conn.cursor().execute("SELECT symbol, timeframe, tp_mult, sl_mult, min_prob, generation FROM agent_logic ORDER BY symbol, timeframe").fetchall()]
 
 
537
  except Exception as e: return [[f"Erreur: {str(e)}", "-", "-", "-", "-", "-"]]
 
538
  def force_scalping_mode():
539
  try:
540
+ with sqlite3.connect(DB_NAME) as conn: conn.execute("UPDATE agent_logic SET tp_mult = 1.8"); conn.commit()
 
 
541
  return get_bot_skills()
542
  except: return [["Erreur", "-", "-", "-", "-", "-"]]
 
543
  def get_active_signals():
544
  try:
545
+ with sqlite3.connect(DB_NAME, timeout=10) as conn:
546
+ conn.row_factory = sqlite3.Row
547
+ return [dict(row) for row in conn.cursor().execute("SELECT * FROM signals WHERE status = 'EN_COURS'").fetchall()]
 
 
548
  except: return []
549
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
550
  # --- 🎨 INTERFACE GRADIO V30 ---
551
  with gr.Blocks(theme=gr.themes.Monochrome()) as iface:
552
+ gr.Markdown("# 🦖 Alpha V30 Dinosaur Engine (Master Edition)")
553
+ with gr.Tab("Admin"): gr.Button("Forcer Entraînement", variant="stop").click(fn=training_wrapper, inputs=gr.Textbox(label="Symbole à recalibrer", value="BTC/USDT"), outputs=gr.Textbox(), api_name="trigger_training")
554
+ with gr.Tab("🎯 Prédictions"): gr.Button("Predict", variant="primary").click(fn=predict_signal, inputs=[gr.Textbox(label="Symbole", value="BTC/USD"), gr.Dropdown(choices=["1m", "5m", "15m", "1h"], value="1h")], outputs=gr.JSON())
 
 
 
 
 
 
 
555
  with gr.Tab("⚖️ Système"):
556
  gr.Button("Judge").click(fn=run_judge_api, outputs=gr.JSON(), api_name="run_judge_api")
557
  gr.Button("Get Active", visible=False).click(fn=get_active_signals, outputs=gr.JSON(), api_name="get_active_signals")
558
  gr.Button("Ping", visible=False).click(fn=keep_alive_ping, outputs=gr.JSON(), api_name="keep_alive_ping")
559
  gr.Button("Set Mode", visible=False).click(fn=set_bot_mode, inputs=gr.Textbox(visible=False), outputs=gr.JSON(), api_name="set_bot_mode")
 
560
  with gr.Tab("📊 Stats (ADN)"):
561
  skills_table = gr.Dataframe(headers=["Marché", "Timeframe", "Cible (TP)", "Risque (SL)", "Peur Min.", "Génération"], value=get_bot_skills(), interactive=False)
562
  with gr.Row():
563
  gr.Button("🔄 Actualiser").click(get_bot_skills, outputs=skills_table)
564
  gr.Button("⚡ Mode Scalping Force").click(force_scalping_mode, outputs=skills_table)
 
565
  gr.Button(visible=False).click(fn=confirm_trade_api, inputs=[gr.Textbox(visible=False), gr.Textbox(visible=False)], outputs=gr.JSON(), api_name="confirm_trade_api")
566
  gr.Button(visible=False).click(fn=cancel_trade_api, inputs=gr.Textbox(visible=False), outputs=gr.JSON(), api_name="cancel_trade_api")
567
  iface.load(get_bot_skills, outputs=skills_table)
568
 
569
  import threading
570
  _auto_pilot_started = False
 
571
  def run_auto_pilot():
572
  global _auto_pilot_started
573
  if _auto_pilot_started: return
574
  _auto_pilot_started = True
575
+ print("⏳ [SYSTEM] Attente 15s avant propulsion Master V30...")
576
+ time.sleep(15)
577
  try:
578
  loop = asyncio.new_event_loop()
579
  asyncio.set_event_loop(loop)
580
+ loop.create_task(universal_scanner_loop())
 
 
581
  loop.create_task(dream_simulation_loop())
582
  loop.run_forever()
583
+ except Exception as e: print(f"⚠️ Erreur Auto-Pilote : {e}")
 
 
 
584
 
585
  if __name__ == "__main__":
586
  try: threading.Thread(target=run_auto_pilot, daemon=True).start()