Riy777 commited on
Commit
8878c1d
·
verified ·
1 Parent(s): fd663b2

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +86 -181
app.py CHANGED
@@ -1,5 +1,5 @@
1
  # ==============================================================================
2
- # 🚀 app.py (V38.1 - GEM-Architect: Colored Diagnostics)
3
  # ==============================================================================
4
 
5
  import os
@@ -45,7 +45,6 @@ try:
45
  from trade_manager import TradeManager
46
  from periodic_tuner import AutoTunerScheduler
47
 
48
- # محاولة استيراد محرك الباكتست (اختياري للتشغيل عبر الواجهة)
49
  try:
50
  from backtest_engine import run_strategic_optimization_task
51
  BACKTEST_AVAILABLE = True
@@ -119,14 +118,6 @@ sys_state = SystemState()
119
  # ------------------------------------------------------------------------------
120
  # Utilities
121
  # ------------------------------------------------------------------------------
122
- def format_crypto_price(price):
123
- if price is None: return "0.0"
124
- try:
125
- p = float(price)
126
- if p == 0: return "0.0"
127
- return "{:.8f}".format(p).rstrip('0').rstrip('.')
128
- except: return str(price)
129
-
130
  def calculate_duration_str(timestamp_str):
131
  if not timestamp_str: return "--:--:--"
132
  try:
@@ -146,6 +137,10 @@ def calculate_duration_str(timestamp_str):
146
  return f"{hours:02}:{minutes:02}:{seconds:02}"
147
  except: return "--:--:--"
148
 
 
 
 
 
149
  # ------------------------------------------------------------------------------
150
  # Auto-Pilot Daemon
151
  # ------------------------------------------------------------------------------
@@ -156,11 +151,9 @@ async def auto_pilot_loop():
156
  await asyncio.sleep(5)
157
  if not sys_state.ready: continue
158
 
159
- # تحديث حالة الـ Adaptive Hub في الواجهة كل دقيقة
160
  if adaptive_hub and int(time.time()) % 60 == 0:
161
  sys_state.training_status_msg = adaptive_hub.get_status()
162
 
163
- # فحص الحراس (Watchdogs) للصفقات المفتوحة
164
  if trade_manager and len(trade_manager.open_positions) > 0:
165
  wd_status = await trade_manager.ensure_active_guardians()
166
  if "No active" not in wd_status:
@@ -168,7 +161,6 @@ async def auto_pilot_loop():
168
  sys_state.last_cycle_logs = trade_manager.latest_guardian_log
169
  continue
170
 
171
- # تشغيل دورة المسح (Cycle) إذا كان الطيار الآلي مفعلاً
172
  if sys_state.auto_pilot and not sys_state.cycle_running and not sys_state.training_running:
173
  if sys_state.last_cycle_time:
174
  elapsed = (datetime.now() - sys_state.last_cycle_time).total_seconds()
@@ -190,15 +182,13 @@ async def auto_pilot_loop():
190
  async def lifespan(app: FastAPI):
191
  global r2, data_manager, ml_processor, adaptive_hub, trade_manager, whale_monitor, news_fetcher, senti_analyzer, sys_state, scheduler
192
 
193
- logger.info("\n🚀 [System] Startup Sequence (Titan V38.1 - Colored Diagnostics)...")
194
  try:
195
- # 1. الخدمات الأساسية
196
  r2 = R2Service()
197
  data_manager = DataManager(contracts_db={}, whale_monitor=None, r2_service=r2)
198
  await data_manager.initialize()
199
  await data_manager.load_contracts_from_r2()
200
 
201
- # 2. المراقبة والتحليل
202
  whale_monitor = EnhancedWhaleMonitor(contracts_db=data_manager.get_contracts_db(), r2_service=r2)
203
  rpc_mgr = AdaptiveRpcManager(data_manager.http_client)
204
  whale_monitor.set_rpc_manager(rpc_mgr)
@@ -207,30 +197,25 @@ async def lifespan(app: FastAPI):
207
  senti_analyzer = SentimentIntensityAnalyzer()
208
  data_manager.whale_monitor = whale_monitor
209
 
210
- # 3. العقل الاستراتيجي (Adaptive Hub)
211
  adaptive_hub = AdaptiveHub(r2_service=r2)
212
  await adaptive_hub.initialize()
213
 
214
- # 4. المعالج العصبي (Processor)
215
  ml_processor = MLProcessor(data_manager=data_manager)
216
  await ml_processor.initialize()
217
 
218
- # 5. مدير التنفيذ (Trade Manager)
219
  trade_manager = TradeManager(r2_service=r2, data_manager=data_manager, processor=ml_processor)
220
  trade_manager.learning_hub = adaptive_hub
221
 
222
  await trade_manager.initialize_sentry_exchanges()
223
  await trade_manager.start_sentry_loops()
224
 
225
- # 6. المجدول التلقائي (Auto-Tuner Scheduler)
226
  scheduler = AutoTunerScheduler(trade_manager)
227
  asyncio.create_task(scheduler.start_loop())
228
  logger.info("🕰️ [Scheduler] Auto-Tuner Background Task Started.")
229
 
230
- # 7. الجاهزية
231
  sys_state.set_ready()
232
  asyncio.create_task(auto_pilot_loop())
233
- logger.info("✅ [System READY] All modules operational. Cybernetic Link Established.")
234
  yield
235
 
236
  except Exception as e:
@@ -244,13 +229,9 @@ async def lifespan(app: FastAPI):
244
  logger.info("✅ [System] Shutdown Complete.")
245
 
246
  # ------------------------------------------------------------------------------
247
- # Helper Tasks (Modified for Context)
248
  # ------------------------------------------------------------------------------
249
  async def _analyze_symbol_task(candidate_data: Dict[str, Any]) -> Dict[str, Any]:
250
- """
251
- Receives full candidate dict from L1 (Regime, Dynamic Limits),
252
- not just the symbol string.
253
- """
254
  try:
255
  symbol = candidate_data['symbol']
256
  required_tfs = ["5m", "15m", "1h", "4h"]
@@ -267,22 +248,23 @@ async def _analyze_symbol_task(candidate_data: Dict[str, Any]) -> Dict[str, Any]
267
 
268
  current_price = await data_manager.get_latest_price_async(symbol)
269
 
270
- # ✅ FIX: Inject Context (Limits & Regime) into raw_data for L2 Processor
271
  raw_data = {
272
  'symbol': symbol,
273
  'ohlcv': ohlcv_data,
274
  'current_price': current_price,
275
  'timestamp': time.time(),
276
- # Preserving L1 Context
277
  'dynamic_limits': candidate_data.get('dynamic_limits', {}),
278
  'asset_regime': candidate_data.get('asset_regime', 'UNKNOWN'),
279
  'strategy_tag': candidate_data.get('strategy_tag', 'NONE'),
 
280
  'l1_score': candidate_data.get('l1_sort_score', 0)
281
  }
282
 
283
  res = await ml_processor.process_compound_signal(raw_data)
284
  if not res: return None
285
-
 
 
286
  return res
287
  except Exception: return None
288
 
@@ -295,15 +277,12 @@ async def run_unified_cycle():
295
  logger.info(message)
296
  log_buffer.write(message + '\n')
297
 
298
- if sys_state.cycle_running or sys_state.training_running:
299
- return
300
- if not sys_state.ready:
301
- return
302
 
303
  sys_state.set_cycle_start()
304
 
305
  try:
306
- # LAYER 0: Guardian & Portfolio Check
307
  await trade_manager.sync_internal_state_with_r2()
308
 
309
  if len(trade_manager.open_positions) > 0:
@@ -314,41 +293,31 @@ async def run_unified_cycle():
314
  pnl = ((curr_p - entry_p) / entry_p) * 100 if entry_p > 0 else 0
315
  log_and_print(f" 🔒 {sym}: {pnl:+.2f}%")
316
 
317
- # LAYER 1: Adaptive Screening
318
- current_regime = getattr(SystemLimits, 'CURRENT_REGIME', 'UNKNOWN')
319
- log_and_print(f" [1/5] 🔍 L1 Screening (Context Aware)...")
320
-
321
- # Pass adaptive_hub so DataManager can fetch DNA per coin
322
  candidates = await data_manager.layer1_rapid_screening(adaptive_hub_ref=adaptive_hub)
323
  if not candidates:
324
  log_and_print("⚠️ No valid candidates found (Quality Filter).")
325
  sys_state.set_cycle_end(logs=log_buffer.getvalue())
326
  return
327
 
328
- # LAYER 2: Deep Analysis
329
  log_and_print(f" [2/5] 🧠 L2 Deep Analysis ({len(candidates)} items)...")
330
- # ✅ FIX: Pass the WHOLE candidate object, not just symbol string
331
  tasks = [_analyze_symbol_task(c) for c in candidates]
332
  results = await asyncio.gather(*tasks)
333
  valid_l2 = [res for res in results if res is not None]
334
 
335
  semi_finalists = sorted(valid_l2, key=lambda x: x.get('enhanced_final_score', 0.0), reverse=True)[:10]
336
-
337
  if not semi_finalists:
338
  log_and_print("⚠️ No valid L2 candidates.")
339
  sys_state.set_cycle_end(logs=log_buffer.getvalue())
340
  return
341
 
342
- # LAYER 3: Deep Dive (Contextual)
343
  log_and_print(f" [3/5] 📡 L3 Deep Dive (Whales & News) for TOP {len(semi_finalists)}...")
344
-
345
  final_candidates = []
346
 
347
  for sig in semi_finalists:
348
  symbol = sig['symbol']
349
  l2_score = sig.get('enhanced_final_score', 0.0)
350
 
351
- # Whale Check
352
  whale_points = 0.0
353
  try:
354
  if whale_monitor:
@@ -362,7 +331,6 @@ async def run_unified_cycle():
362
  elif action == 'SELL': whale_points = -dynamic_impact
363
  except Exception: pass
364
 
365
- # News Check
366
  news_points = 0.0
367
  try:
368
  if news_fetcher and senti_analyzer:
@@ -374,7 +342,6 @@ async def run_unified_cycle():
374
  news_points = compound_score * SystemLimits.L3_NEWS_IMPACT_MAX
375
  except Exception: pass
376
 
377
- # MC Advanced
378
  mc_a_points = 0.0
379
  try:
380
  raw_mc_a = await ml_processor.run_advanced_monte_carlo(symbol, '1h')
@@ -382,30 +349,18 @@ async def run_unified_cycle():
382
  except Exception: pass
383
 
384
  final_score = l2_score + whale_points + news_points + mc_a_points
385
-
386
- sig['whale_score'] = whale_points
387
- sig['news_score'] = news_points
388
- sig['mc_advanced_score'] = mc_a_points
389
  sig['final_total_score'] = final_score
390
-
391
  final_candidates.append(sig)
392
 
393
- # RE-RANKING
394
  final_candidates.sort(key=lambda x: x['final_total_score'], reverse=True)
395
 
396
  approved_signals = []
397
-
398
- header = (f"{'SYM':<9} | {'L2(HYB)':<6} | {'TITAN':<5} | {'PATT':<5} | "
399
- f"{'WHALE':<6} | {'MC(A)':<6} | {'FINAL':<6} | {'ORACLE':<6} | {'STATUS'}")
400
- log_and_print("-" * 110)
401
- log_and_print(header)
402
  log_and_print("-" * 110)
 
403
 
404
  for sig in final_candidates:
405
  symbol = sig['symbol']
406
-
407
  decision = await ml_processor.consult_oracle(sig)
408
-
409
  action = decision.get('action', 'WAIT')
410
  oracle_conf = decision.get('confidence', 0.0)
411
  target_class = decision.get('target_class', '')
@@ -416,26 +371,8 @@ async def run_unified_cycle():
416
  sig.update(decision)
417
  approved_signals.append(sig)
418
 
419
- l2_hybrid = sig.get('enhanced_final_score', 0.0)
420
- titan_d = sig.get('titan_score', 0.0)
421
- patt_d = sig.get('patterns_score', 0.0)
422
- whale_d = sig.get('whale_score', 0.0)
423
- mca_d = sig.get('mc_advanced_score', 0.0)
424
- final_d = sig.get('final_total_score', 0.0)
425
-
426
- log_and_print(
427
- f"{symbol:<9} | "
428
- f"{l2_hybrid:.2f} | "
429
- f"{titan_d:.2f} | "
430
- f"{patt_d:.2f} | "
431
- f"{whale_d:+.2f} | "
432
- f"{mca_d:+.2f} | "
433
- f"{final_d:.2f} | "
434
- f"{oracle_conf:.2f} | "
435
- f"{status_str}"
436
- )
437
-
438
- # LAYER 4: Sniper & Governance & Execution
439
  if approved_signals:
440
  log_and_print("-" * 110)
441
  log_and_print(f" [4/5] 🎯 L4 Sniper -> 🏛️ Governance -> 💰 Portfolio ({len(approved_signals)} candidates)...")
@@ -462,38 +399,29 @@ async def run_unified_cycle():
462
  # Handlers
463
  # ------------------------------------------------------------------------------
464
  async def trigger_training_cycle():
465
- if adaptive_hub:
466
- status = adaptive_hub.get_status()
467
- return f"🤖 Adaptive System: {status}"
468
  return "⚠️ System not ready."
469
 
470
  async def trigger_strategic_backtest():
471
- if not BACKTEST_AVAILABLE:
472
- return "⚠️ Backtest Engine not found."
473
-
474
- if trade_manager and len(trade_manager.open_positions) > 0:
475
- return "⛔ Cannot start Backtest: Active trades exist! Close them first."
476
-
477
- if sys_state.training_running:
478
- return "⚠️ Training already in progress."
479
 
480
  async def _run_bg_task():
481
  sys_state.training_running = True
482
  sys_state.training_status_msg = "🧪 Strategic Backtest Running..."
483
  try:
484
- logger.info("🧪 [Manual Trigger] Starting Strategic Backtest...")
485
  await run_strategic_optimization_task()
486
- if adaptive_hub:
487
- await adaptive_hub.initialize()
488
- logger.info(" [Manual Trigger] Backtest Complete. DNA Updated.")
489
- except Exception as e:
490
- logger.error(f"❌ Backtest Failed: {e}")
491
  finally:
492
  sys_state.training_running = False
493
  sys_state.training_status_msg = adaptive_hub.get_status() if adaptive_hub else "Ready"
494
 
495
  asyncio.create_task(_run_bg_task())
496
- return "🧪 Strategic Backtest Started (Safe Mode)."
497
 
498
  async def manual_close_current_trade():
499
  if not trade_manager.open_positions: return "⚠️ No trade."
@@ -528,16 +456,13 @@ async def reset_capital_handler():
528
  await sp._save_state_to_r2()
529
  return f"✅ Capital Reset to ${INITIAL_CAPITAL} (History Kept)"
530
 
531
- # 🔥 زر تصفير مصفوفة التشخيص
532
  async def reset_diagnostics_handler():
533
  await r2.reset_diagnostic_stats_async()
534
  return "✅ Diagnostic Matrix Reset."
535
 
536
- # 🔥 زر تصفير إحصائيات الحراس
537
  async def reset_guardians_handler():
538
  await r2.reset_guardian_stats_async()
539
- if trade_manager:
540
- trade_manager.ai_stats = await r2.get_guardian_stats_async()
541
  return "✅ Guardian Stats Reset."
542
 
543
  async def toggle_auto_pilot(enable):
@@ -550,16 +475,17 @@ async def run_cycle_from_gradio():
550
  return "🚀 Launched."
551
 
552
  # ------------------------------------------------------------------------------
553
- # UI Updates (Updated for Diagnostics Coloring)
554
  # ------------------------------------------------------------------------------
555
  async def check_live_pnl_and_status(selected_view="Dual-Core (Hybrid)"):
556
  empty_chart = go.Figure()
557
  empty_chart.update_layout(template="plotly_dark", paper_bgcolor="#0b0f19", plot_bgcolor="#0b0f19", xaxis={'visible':False}, yaxis={'visible':False})
558
  wl_df_empty = pd.DataFrame(columns=["Coin", "Score"])
559
  diag_df_empty = pd.DataFrame(columns=["Model", "Wins", "Losses", "PnL (USD)"])
 
560
 
561
  if not sys_state.ready:
562
- return "Initializing...", "...", empty_chart, "0.0", "0.0", "0.0", "0.0", "0.0%", wl_df_empty, diag_df_empty, "Loading...", "Loading...", "Loading..."
563
 
564
  try:
565
  sp = trade_manager.smart_portfolio
@@ -568,8 +494,6 @@ async def check_live_pnl_and_status(selected_view="Dual-Core (Hybrid)"):
568
  free_cap = max(0.0, equity - allocated)
569
  daily_pnl = sp.state.get('daily_net_pnl', 0.0)
570
  is_halted = sp.state.get('is_trading_halted', False)
571
- market_mood = sp.market_trend
572
- fg_index = sp.fear_greed_index
573
 
574
  symbol = None; entry_p = 0.0; tp_p = 0.0; sl_p = 0.0; curr_p = 0.0; pnl_pct = 0.0; pnl_val_unrealized = 0.0
575
  active_trade_info = ""
@@ -583,19 +507,18 @@ async def check_live_pnl_and_status(selected_view="Dual-Core (Hybrid)"):
583
  sl_p = float(trade.get('sl_price', 0.0))
584
  trade_dur_str = calculate_duration_str(trade.get('entry_time'))
585
 
586
- # ✅ استخراج بيانات الحوكمة والقرار
587
  decision_data = trade.get('decision_data', {})
588
  gov_grade = decision_data.get('governance_grade', 'N/A')
589
  gov_score = decision_data.get('governance_score', 0.0)
590
  sys_conf = decision_data.get('system_confidence', 0.0)
 
591
 
592
- # تلوين الرتبة حسب الجودة
593
  grade_color = "#ccc"
594
- if gov_grade == "ULTRA": grade_color = "#ff00ff" # Magenta
595
- elif gov_grade == "STRONG": grade_color = "#00ff00" # Green
596
- elif gov_grade == "NORMAL": grade_color = "#00e5ff" # Cyan
597
- elif gov_grade == "WEAK": grade_color = "#ffff00" # Yellow
598
- elif gov_grade == "REJECT": grade_color = "#ff0000" # Red
599
 
600
  curr_p = await data_manager.get_latest_price_async(symbol)
601
  if curr_p > 0 and entry_p > 0:
@@ -608,16 +531,15 @@ async def check_live_pnl_and_status(selected_view="Dual-Core (Hybrid)"):
608
  <span>⏱️ Time:</span> <span style='color: #ffff00;'>{trade_dur_str}</span>
609
  </div>
610
  <div style='display: flex; justify-content: space-between; font-size: 12px; color: #ccc; margin-top:5px;'>
611
- <span>🏛️ Gov Grade:</span> <span style='color: {grade_color}; font-weight:bold;'>{gov_grade} ({gov_score:.1f})</span>
612
  </div>
613
  <div style='display: flex; justify-content: space-between; font-size: 12px; color: #ccc; margin-top:5px;'>
614
- <span>🔮 System Conf:</span> <span style='color: #00e5ff;'>{sys_conf:.1%}</span>
615
  </div>
616
  """
617
 
618
  virtual_equity = equity + pnl_val_unrealized
619
- active_trade_pnl_val = pnl_val_unrealized
620
- active_pnl_color = "#00ff00" if active_trade_pnl_val >= 0 else "#ff0000"
621
  portfolio = await r2.get_portfolio_state_async()
622
  total_t = portfolio.get('total_trades', 0)
623
  wins = portfolio.get('winning_trades', 0)
@@ -627,29 +549,24 @@ async def check_live_pnl_and_status(selected_view="Dual-Core (Hybrid)"):
627
  tot_loss = portfolio.get('total_loss_usd', 0.0)
628
  net_prof = tot_prof - tot_loss
629
  win_rate = (wins / total_t * 100) if total_t > 0 else 0.0
630
- color = "#00ff00" if daily_pnl >= 0 else "#ff0000"
631
  halt_status = "<span style='color:red; font-weight:bold;'>HALTED</span>" if is_halted else "<span style='color:#00ff00;'>ACTIVE</span>"
632
- current_regime = getattr(SystemLimits, 'CURRENT_REGIME', 'N/A')
633
 
634
  wallet_md = f"""
635
  <div style='background-color: #1a1a1a; padding: 15px; border-radius: 8px; border: 1px solid #333; text-align:center;'>
636
  <h3 style='margin:0; color:#888; font-size:14px;'>💼 Institutional Portfolio</h3>
637
  <div style='font-size: 24px; font-weight: bold; color: white; margin: 5px 0 0 0;'>${virtual_equity:,.2f}</div>
638
- <div style='font-size: 14px; color: {active_pnl_color}; margin-bottom: 5px;'>({active_trade_pnl_val:+,.2f} USD)</div>
639
 
640
  <table style='width:100%; font-size:12px; margin-top:5px; color:#ccc;'>
641
  <tr><td>Allocated:</td><td style='text-align:right; color:#ffa500;'>${allocated:.2f}</td></tr>
642
  <tr><td>Free Cap:</td><td style='text-align:right; color:#00ff00;'>${free_cap:.2f}</td></tr>
643
- <tr><td>Daily PnL:</td><td style='text-align:right; color:{color};'>${daily_pnl:+.2f}</td></tr>
644
  </table>
645
 
646
  <hr style='border-color:#444; margin: 10px 0;'>
647
 
648
  <div style='display: flex; justify-content: space-between; font-size: 12px; color: #ccc;'>
649
- <span>🦅 Mood:</span> <span style='color: white;'>{market_mood} ({fg_index})</span>
650
- </div>
651
- <div style='display: flex; justify-content: space-between; font-size: 12px; color: #ccc; margin-top:3px;'>
652
- <span>🧬 Regime:</span> <span style='color: #00e5ff; font-weight:bold;'>{current_regime}</span>
653
  </div>
654
  <div style='display: flex; justify-content: space-between; font-size: 12px; color: #ccc; margin-top:5px;'>
655
  <span>🛡️ Status:</span> {halt_status}
@@ -658,6 +575,7 @@ async def check_live_pnl_and_status(selected_view="Dual-Core (Hybrid)"):
658
  </div>
659
  """
660
 
 
661
  key_map = {
662
  "Dual-Core (Hybrid)": "hybrid",
663
  "Hydra: Crash (Panic)": "crash",
@@ -665,7 +583,6 @@ async def check_live_pnl_and_status(selected_view="Dual-Core (Hybrid)"):
665
  "Hydra: Stagnation (Time)": "stagnation"
666
  }
667
  target_key = key_map.get(selected_view, "hybrid")
668
- # استخدام النسخة الموجودة في TradeManager مباشرة لضمان الحداثة
669
  stats_data = trade_manager.ai_stats.get(target_key, {"total":0, "good":0, "saved":0.0, "missed":0.0})
670
 
671
  tot_ds = stats_data['total']
@@ -687,7 +604,6 @@ async def check_live_pnl_and_status(selected_view="Dual-Core (Hybrid)"):
687
  <tr><td>Interventions:</td><td style='text-align:right;'>{tot_ds}</td></tr>
688
  <tr><td>Accuracy:</td><td style='text-align:right; color:#00e5ff;'>{ds_acc:.1f}%</td></tr>
689
  <tr><td>Saved:</td><td style='text-align:right; color:#00ff00;'>${stats_data['saved']:.2f}</td></tr>
690
- <tr><td>Missed:</td><td style='text-align:right; color:#ff0000;'>${stats_data['missed']:.2f}</td></tr>
691
  </table>
692
  </div>
693
  """
@@ -696,74 +612,57 @@ async def check_live_pnl_and_status(selected_view="Dual-Core (Hybrid)"):
696
  if adaptive_hub:
697
  if hasattr(adaptive_hub, 'get_learning_progress'):
698
  fast_learn_prog = adaptive_hub.get_learning_progress()
699
- else:
700
- fast_learn_prog = "N/A"
701
-
702
- sch_w_time = "Wait"; sch_w_cnt = 0
703
- sch_m_time = "Wait"; sch_m_cnt = 0
704
- sch_running = False
705
 
706
- if scheduler:
707
- metrics = scheduler.get_status_metrics()
708
- sch_w_time = metrics["weekly_timer"]
709
- sch_w_cnt = metrics["weekly_count"]
710
- sch_m_time = metrics["monthly_timer"]
711
- sch_m_cnt = metrics["monthly_count"]
712
- sch_running = metrics["is_running"]
713
-
714
- running_badge = "<span style='color:#00ff00; float:right; animation: blink 1s infinite;'>RUNNING ⚙️</span>" if sch_running else ""
715
 
716
  neural_md = f"""
717
  <div style='background-color: #1a1a1a; padding: 10px; border-radius: 8px; border: 1px solid #333; font-size: 12px; margin-top: 10px;'>
718
- <div style='display:flex; justify-content:space-between; align-items:center; margin-bottom:5px;'>
719
- <h3 style='margin:0; color:#00e5ff; font-size:14px;'>🧠 Neural Cycles</h3>
720
- {running_badge}
721
- </div>
722
  <table style='width:100%; color:#ccc;'>
723
  <tr style='border-bottom: 1px solid #333;'>
724
  <td style='padding:4px 0;'>⚡ Fast Learner:</td>
725
  <td style='text-align:right; color:#ffff00; font-weight:bold;'>{fast_learn_prog}</td>
726
- <td style='text-align:right; font-size:10px; color:#666;'>Trades</td>
727
  </tr>
728
  <tr style='border-bottom: 1px solid #333;'>
729
  <td style='padding:4px 0;'>📅 Weekly Tune:</td>
730
  <td style='text-align:right; color:#fff;'>{sch_w_time}</td>
731
- <td style='text-align:right; color:#00ff00;'>#{sch_w_cnt}</td>
732
- </tr>
733
- <tr>
734
- <td style='padding:4px 0;'>🗓️ Monthly Evo:</td>
735
- <td style='text-align:right; color:#fff;'>{sch_m_time}</td>
736
- <td style='text-align:right; color:#00ff00;'>#{sch_m_cnt}</td>
737
  </tr>
738
  </table>
739
- <div style='margin-top:5px; font-size:10px; color:#555; text-align:center;'>
740
- Adaptive DNA Active: {getattr(SystemLimits, 'CURRENT_REGIME', 'N/A')}
741
- </div>
742
  </div>
743
  """
744
 
745
- # 🔥 جلب بيانات مصفوفة التشخيص وتلوينها
746
  diag_data = await r2.get_diagnostic_stats_async()
747
  diag_list = []
748
- ordered_models = ["Titan", "Patterns", "Oracle", "Sniper", "MonteCarlo_L", "MonteCarlo_A", "Governance"]
749
 
750
  for m in ordered_models:
751
  stats = diag_data.get(m, {"wins": 0, "losses": 0, "pnl": 0.0})
752
  pnl_val = stats['pnl']
753
-
754
- # 🎨 التلوين: أخضر للربح، أحمر للخسارة
755
  color = "#00ff00" if pnl_val >= 0 else "#ff0000"
756
  pnl_str = f"<span style='color: {color}; font-weight: bold;'>${pnl_val:+.2f}</span>"
757
-
758
- diag_list.append([
759
- m,
760
- stats['wins'],
761
- stats['losses'],
762
- pnl_str
763
- ])
764
 
765
  diag_df = pd.DataFrame(diag_list, columns=["Model", "Wins", "Losses", "PnL (USD)"])
766
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
767
  wl_data = [[k, f"{v.get('final_total_score',0):.2f}"] for k, v in trade_manager.watchlist.items()]
768
  wl_df = pd.DataFrame(wl_data, columns=["Coin", "Score"])
769
 
@@ -783,9 +682,9 @@ async def check_live_pnl_and_status(selected_view="Dual-Core (Hybrid)"):
783
  if entry_p > 0:
784
  fig.add_hline(y=entry_p, line_dash="dash", line_color="white", annotation_text="ENTRY", annotation_position="top left")
785
  if tp_p > 0:
786
- fig.add_hline(y=tp_p, line_color="#00ff00", line_width=2, annotation_text="TARGET (TP)", annotation_position="top left")
787
  if sl_p > 0:
788
- fig.add_hline(y=sl_p, line_color="#ff0000", line_width=2, annotation_text="STOP LOSS", annotation_position="bottom left")
789
 
790
  fig.update_layout(
791
  template="plotly_dark",
@@ -794,19 +693,18 @@ async def check_live_pnl_and_status(selected_view="Dual-Core (Hybrid)"):
794
  margin=dict(l=0, r=40, t=30, b=0),
795
  height=400,
796
  xaxis_rangeslider_visible=False,
797
- title=dict(text=f"{symbol} (Spot Long) | PnL: {pnl_pct:+.2f}%", font=dict(color="white"))
798
  )
799
 
800
  train_status = sys_state.training_status_msg
801
  if sys_state.training_running: train_status = "🧪 Backtest Running..."
802
 
803
- # إضافة diag_df إلى مخرجات الدالة
804
  return (status_txt, status_line, fig, f"{curr_p:.6f}", f"{entry_p:.6f}", f"{tp_p:.6f}", f"{sl_p:.6f}",
805
- f"{pnl_pct:+.2f}%", wl_df, diag_df, wallet_md, history_md, neural_md)
806
 
807
  except Exception:
808
  traceback.print_exc()
809
- return "Error", "Error", empty_chart, "0", "0", "0", "0", "0%", wl_df_empty, diag_df_empty, "Err", "Err", "Err"
810
 
811
  # ------------------------------------------------------------------------------
812
  # Gradio UI Construction
@@ -814,10 +712,10 @@ async def check_live_pnl_and_status(selected_view="Dual-Core (Hybrid)"):
814
  def create_gradio_ui():
815
  custom_css = ".gradio-container {background:#0b0f19} .dataframe {background:#1a1a1a!important} .html-box {min-height:180px}"
816
 
817
- with gr.Blocks(title="Titan V38.1 (Neural Dashboard)") as demo:
818
  gr.HTML(f"<style>{custom_css}</style>")
819
 
820
- gr.Markdown("# 🚀 Titan V38.1 (Cybernetic: Neural Dashboard)")
821
 
822
  with gr.Row():
823
  with gr.Column(scale=3):
@@ -834,11 +732,19 @@ def create_gradio_ui():
834
  wallet_out = gr.HTML(label="Smart Wallet", elem_classes="html-box")
835
  neural_out = gr.HTML(label="Neural Cycles", elem_classes="html-box")
836
 
837
- # 🔥 إضافة مصفوفة التشخيص الجديدة مع دعم HTML للألوان
 
 
 
 
 
 
 
 
838
  gr.Markdown("### 🕵️ Diagnostic Matrix")
839
  diagnostic_out = gr.Dataframe(
840
  headers=["Model", "Wins", "Losses", "PnL (USD)"],
841
- datatype=["str", "number", "number", "html"], # ✅ html لتفعيل الألوان
842
  interactive=False,
843
  label="Model Performance"
844
  )
@@ -880,7 +786,6 @@ def create_gradio_ui():
880
  logs = gr.Textbox(label="Logs", lines=14, autoscroll=True, elem_classes="log-box", type="text")
881
  gr.HTML("<style>.log-box textarea { font-family: 'Consolas', 'Monaco', monospace !important; font-size: 12px !important; white-space: pre !important; }</style>")
882
 
883
- # Event Handlers
884
  btn_run.click(fn=run_cycle_from_gradio, outputs=alert)
885
  btn_close.click(fn=manual_close_current_trade, outputs=alert)
886
  btn_history_reset.click(fn=reset_history_handler, outputs=alert)
@@ -889,12 +794,12 @@ def create_gradio_ui():
889
  btn_backtest.click(fn=trigger_strategic_backtest, outputs=alert)
890
  auto_pilot.change(fn=toggle_auto_pilot, inputs=auto_pilot, outputs=alert)
891
 
892
- # ربط أزرار التصفير الجديدة
893
  btn_reset_diag.click(fn=reset_diagnostics_handler, outputs=alert)
894
  btn_reset_guard.click(fn=reset_guardians_handler, outputs=alert)
895
 
 
896
  gr.Timer(3).tick(fn=check_live_pnl_and_status, inputs=stats_dd,
897
- outputs=[logs, status, live_chart, t_price, t_entry, t_tp, t_sl, t_pnl, watchlist_out, diagnostic_out, wallet_out, history_out, neural_out])
898
  return demo
899
 
900
  fast_api_server = FastAPI(lifespan=lifespan)
 
1
  # ==============================================================================
2
+ # 🚀 app.py (V61.0 - GEM-Architect: Type Stats UI)
3
  # ==============================================================================
4
 
5
  import os
 
45
  from trade_manager import TradeManager
46
  from periodic_tuner import AutoTunerScheduler
47
 
 
48
  try:
49
  from backtest_engine import run_strategic_optimization_task
50
  BACKTEST_AVAILABLE = True
 
118
  # ------------------------------------------------------------------------------
119
  # Utilities
120
  # ------------------------------------------------------------------------------
 
 
 
 
 
 
 
 
121
  def calculate_duration_str(timestamp_str):
122
  if not timestamp_str: return "--:--:--"
123
  try:
 
137
  return f"{hours:02}:{minutes:02}:{seconds:02}"
138
  except: return "--:--:--"
139
 
140
+ def format_pnl_split(profit, loss):
141
+ """تنسيق الربحية كجزأين (ربح / خسارة) بألوان"""
142
+ return f"<span style='color:#00ff00'>+${profit:,.0f}</span> / <span style='color:#ff0000'>-${abs(loss):,.0f}</span>"
143
+
144
  # ------------------------------------------------------------------------------
145
  # Auto-Pilot Daemon
146
  # ------------------------------------------------------------------------------
 
151
  await asyncio.sleep(5)
152
  if not sys_state.ready: continue
153
 
 
154
  if adaptive_hub and int(time.time()) % 60 == 0:
155
  sys_state.training_status_msg = adaptive_hub.get_status()
156
 
 
157
  if trade_manager and len(trade_manager.open_positions) > 0:
158
  wd_status = await trade_manager.ensure_active_guardians()
159
  if "No active" not in wd_status:
 
161
  sys_state.last_cycle_logs = trade_manager.latest_guardian_log
162
  continue
163
 
 
164
  if sys_state.auto_pilot and not sys_state.cycle_running and not sys_state.training_running:
165
  if sys_state.last_cycle_time:
166
  elapsed = (datetime.now() - sys_state.last_cycle_time).total_seconds()
 
182
  async def lifespan(app: FastAPI):
183
  global r2, data_manager, ml_processor, adaptive_hub, trade_manager, whale_monitor, news_fetcher, senti_analyzer, sys_state, scheduler
184
 
185
+ logger.info("\n🚀 [System] Startup Sequence (Titan V61.0 - Dual Classification)...")
186
  try:
 
187
  r2 = R2Service()
188
  data_manager = DataManager(contracts_db={}, whale_monitor=None, r2_service=r2)
189
  await data_manager.initialize()
190
  await data_manager.load_contracts_from_r2()
191
 
 
192
  whale_monitor = EnhancedWhaleMonitor(contracts_db=data_manager.get_contracts_db(), r2_service=r2)
193
  rpc_mgr = AdaptiveRpcManager(data_manager.http_client)
194
  whale_monitor.set_rpc_manager(rpc_mgr)
 
197
  senti_analyzer = SentimentIntensityAnalyzer()
198
  data_manager.whale_monitor = whale_monitor
199
 
 
200
  adaptive_hub = AdaptiveHub(r2_service=r2)
201
  await adaptive_hub.initialize()
202
 
 
203
  ml_processor = MLProcessor(data_manager=data_manager)
204
  await ml_processor.initialize()
205
 
 
206
  trade_manager = TradeManager(r2_service=r2, data_manager=data_manager, processor=ml_processor)
207
  trade_manager.learning_hub = adaptive_hub
208
 
209
  await trade_manager.initialize_sentry_exchanges()
210
  await trade_manager.start_sentry_loops()
211
 
 
212
  scheduler = AutoTunerScheduler(trade_manager)
213
  asyncio.create_task(scheduler.start_loop())
214
  logger.info("🕰️ [Scheduler] Auto-Tuner Background Task Started.")
215
 
 
216
  sys_state.set_ready()
217
  asyncio.create_task(auto_pilot_loop())
218
+ logger.info("✅ [System READY] All modules operational.")
219
  yield
220
 
221
  except Exception as e:
 
229
  logger.info("✅ [System] Shutdown Complete.")
230
 
231
  # ------------------------------------------------------------------------------
232
+ # Helper Tasks
233
  # ------------------------------------------------------------------------------
234
  async def _analyze_symbol_task(candidate_data: Dict[str, Any]) -> Dict[str, Any]:
 
 
 
 
235
  try:
236
  symbol = candidate_data['symbol']
237
  required_tfs = ["5m", "15m", "1h", "4h"]
 
248
 
249
  current_price = await data_manager.get_latest_price_async(symbol)
250
 
 
251
  raw_data = {
252
  'symbol': symbol,
253
  'ohlcv': ohlcv_data,
254
  'current_price': current_price,
255
  'timestamp': time.time(),
 
256
  'dynamic_limits': candidate_data.get('dynamic_limits', {}),
257
  'asset_regime': candidate_data.get('asset_regime', 'UNKNOWN'),
258
  'strategy_tag': candidate_data.get('strategy_tag', 'NONE'),
259
+ 'strategy_type': candidate_data.get('strategy_type', 'NORMAL'), # Passing Type
260
  'l1_score': candidate_data.get('l1_sort_score', 0)
261
  }
262
 
263
  res = await ml_processor.process_compound_signal(raw_data)
264
  if not res: return None
265
+
266
+ # Pass Type Forward
267
+ res['strategy_type'] = candidate_data.get('strategy_type', 'NORMAL')
268
  return res
269
  except Exception: return None
270
 
 
277
  logger.info(message)
278
  log_buffer.write(message + '\n')
279
 
280
+ if sys_state.cycle_running or sys_state.training_running: return
281
+ if not sys_state.ready: return
 
 
282
 
283
  sys_state.set_cycle_start()
284
 
285
  try:
 
286
  await trade_manager.sync_internal_state_with_r2()
287
 
288
  if len(trade_manager.open_positions) > 0:
 
293
  pnl = ((curr_p - entry_p) / entry_p) * 100 if entry_p > 0 else 0
294
  log_and_print(f" 🔒 {sym}: {pnl:+.2f}%")
295
 
296
+ log_and_print(f" [1/5] 🔍 L1 Screening (Bottom/Momentum)...")
 
 
 
 
297
  candidates = await data_manager.layer1_rapid_screening(adaptive_hub_ref=adaptive_hub)
298
  if not candidates:
299
  log_and_print("⚠️ No valid candidates found (Quality Filter).")
300
  sys_state.set_cycle_end(logs=log_buffer.getvalue())
301
  return
302
 
 
303
  log_and_print(f" [2/5] 🧠 L2 Deep Analysis ({len(candidates)} items)...")
 
304
  tasks = [_analyze_symbol_task(c) for c in candidates]
305
  results = await asyncio.gather(*tasks)
306
  valid_l2 = [res for res in results if res is not None]
307
 
308
  semi_finalists = sorted(valid_l2, key=lambda x: x.get('enhanced_final_score', 0.0), reverse=True)[:10]
 
309
  if not semi_finalists:
310
  log_and_print("⚠️ No valid L2 candidates.")
311
  sys_state.set_cycle_end(logs=log_buffer.getvalue())
312
  return
313
 
 
314
  log_and_print(f" [3/5] 📡 L3 Deep Dive (Whales & News) for TOP {len(semi_finalists)}...")
 
315
  final_candidates = []
316
 
317
  for sig in semi_finalists:
318
  symbol = sig['symbol']
319
  l2_score = sig.get('enhanced_final_score', 0.0)
320
 
 
321
  whale_points = 0.0
322
  try:
323
  if whale_monitor:
 
331
  elif action == 'SELL': whale_points = -dynamic_impact
332
  except Exception: pass
333
 
 
334
  news_points = 0.0
335
  try:
336
  if news_fetcher and senti_analyzer:
 
342
  news_points = compound_score * SystemLimits.L3_NEWS_IMPACT_MAX
343
  except Exception: pass
344
 
 
345
  mc_a_points = 0.0
346
  try:
347
  raw_mc_a = await ml_processor.run_advanced_monte_carlo(symbol, '1h')
 
349
  except Exception: pass
350
 
351
  final_score = l2_score + whale_points + news_points + mc_a_points
 
 
 
 
352
  sig['final_total_score'] = final_score
 
353
  final_candidates.append(sig)
354
 
 
355
  final_candidates.sort(key=lambda x: x['final_total_score'], reverse=True)
356
 
357
  approved_signals = []
 
 
 
 
 
358
  log_and_print("-" * 110)
359
+ log_and_print(f"{'SYM':<9} | {'TYPE':<12} | {'FINAL':<6} | {'ORACLE':<6} | {'STATUS'}")
360
 
361
  for sig in final_candidates:
362
  symbol = sig['symbol']
 
363
  decision = await ml_processor.consult_oracle(sig)
 
364
  action = decision.get('action', 'WAIT')
365
  oracle_conf = decision.get('confidence', 0.0)
366
  target_class = decision.get('target_class', '')
 
371
  sig.update(decision)
372
  approved_signals.append(sig)
373
 
374
+ log_and_print(f"{symbol:<9} | {sig.get('strategy_type','N/A'):<12} | {sig.get('final_total_score',0):.2f} | {oracle_conf:.2f} | {status_str}")
375
+
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
376
  if approved_signals:
377
  log_and_print("-" * 110)
378
  log_and_print(f" [4/5] 🎯 L4 Sniper -> 🏛️ Governance -> 💰 Portfolio ({len(approved_signals)} candidates)...")
 
399
  # Handlers
400
  # ------------------------------------------------------------------------------
401
  async def trigger_training_cycle():
402
+ if adaptive_hub: return f"🤖 Adaptive System: {adaptive_hub.get_status()}"
 
 
403
  return "⚠️ System not ready."
404
 
405
  async def trigger_strategic_backtest():
406
+ if not BACKTEST_AVAILABLE: return "⚠️ Backtest Engine not found."
407
+ if trade_manager and len(trade_manager.open_positions) > 0: return " Active trades exist."
408
+ if sys_state.training_running: return "⚠️ Running."
 
 
 
 
 
409
 
410
  async def _run_bg_task():
411
  sys_state.training_running = True
412
  sys_state.training_status_msg = "🧪 Strategic Backtest Running..."
413
  try:
414
+ logger.info("🧪 [Manual] Starting Strategic Backtest...")
415
  await run_strategic_optimization_task()
416
+ if adaptive_hub: await adaptive_hub.initialize()
417
+ logger.info("✅ [Manual] Backtest Complete.")
418
+ except Exception as e: logger.error(f" Backtest Failed: {e}")
 
 
419
  finally:
420
  sys_state.training_running = False
421
  sys_state.training_status_msg = adaptive_hub.get_status() if adaptive_hub else "Ready"
422
 
423
  asyncio.create_task(_run_bg_task())
424
+ return "🧪 Strategic Backtest Started."
425
 
426
  async def manual_close_current_trade():
427
  if not trade_manager.open_positions: return "⚠️ No trade."
 
456
  await sp._save_state_to_r2()
457
  return f"✅ Capital Reset to ${INITIAL_CAPITAL} (History Kept)"
458
 
 
459
  async def reset_diagnostics_handler():
460
  await r2.reset_diagnostic_stats_async()
461
  return "✅ Diagnostic Matrix Reset."
462
 
 
463
  async def reset_guardians_handler():
464
  await r2.reset_guardian_stats_async()
465
+ if trade_manager: trade_manager.ai_stats = await r2.get_guardian_stats_async()
 
466
  return "✅ Guardian Stats Reset."
467
 
468
  async def toggle_auto_pilot(enable):
 
475
  return "🚀 Launched."
476
 
477
  # ------------------------------------------------------------------------------
478
+ # UI Updates
479
  # ------------------------------------------------------------------------------
480
  async def check_live_pnl_and_status(selected_view="Dual-Core (Hybrid)"):
481
  empty_chart = go.Figure()
482
  empty_chart.update_layout(template="plotly_dark", paper_bgcolor="#0b0f19", plot_bgcolor="#0b0f19", xaxis={'visible':False}, yaxis={'visible':False})
483
  wl_df_empty = pd.DataFrame(columns=["Coin", "Score"])
484
  diag_df_empty = pd.DataFrame(columns=["Model", "Wins", "Losses", "PnL (USD)"])
485
+ type_df_empty = pd.DataFrame(columns=["Coin Type", "Wins", "Losses", "Profitability"])
486
 
487
  if not sys_state.ready:
488
+ return "Initializing...", "...", empty_chart, "0.0", "0.0", "0.0", "0.0", "0.0%", wl_df_empty, diag_df_empty, type_df_empty, "Loading...", "Loading...", "Loading..."
489
 
490
  try:
491
  sp = trade_manager.smart_portfolio
 
494
  free_cap = max(0.0, equity - allocated)
495
  daily_pnl = sp.state.get('daily_net_pnl', 0.0)
496
  is_halted = sp.state.get('is_trading_halted', False)
 
 
497
 
498
  symbol = None; entry_p = 0.0; tp_p = 0.0; sl_p = 0.0; curr_p = 0.0; pnl_pct = 0.0; pnl_val_unrealized = 0.0
499
  active_trade_info = ""
 
507
  sl_p = float(trade.get('sl_price', 0.0))
508
  trade_dur_str = calculate_duration_str(trade.get('entry_time'))
509
 
 
510
  decision_data = trade.get('decision_data', {})
511
  gov_grade = decision_data.get('governance_grade', 'N/A')
512
  gov_score = decision_data.get('governance_score', 0.0)
513
  sys_conf = decision_data.get('system_confidence', 0.0)
514
+ strat_type = trade.get('strategy_type', 'NORMAL')
515
 
 
516
  grade_color = "#ccc"
517
+ if gov_grade == "ULTRA": grade_color = "#ff00ff"
518
+ elif gov_grade == "STRONG": grade_color = "#00ff00"
519
+ elif gov_grade == "NORMAL": grade_color = "#00e5ff"
520
+ elif gov_grade == "WEAK": grade_color = "#ffff00"
521
+ elif gov_grade == "REJECT": grade_color = "#ff0000"
522
 
523
  curr_p = await data_manager.get_latest_price_async(symbol)
524
  if curr_p > 0 and entry_p > 0:
 
531
  <span>⏱️ Time:</span> <span style='color: #ffff00;'>{trade_dur_str}</span>
532
  </div>
533
  <div style='display: flex; justify-content: space-between; font-size: 12px; color: #ccc; margin-top:5px;'>
534
+ <span>🏛️ Grade:</span> <span style='color: {grade_color}; font-weight:bold;'>{gov_grade} ({gov_score:.1f})</span>
535
  </div>
536
  <div style='display: flex; justify-content: space-between; font-size: 12px; color: #ccc; margin-top:5px;'>
537
+ <span>🏷️ Type:</span> <span style='color: #orange;'>{strat_type}</span>
538
  </div>
539
  """
540
 
541
  virtual_equity = equity + pnl_val_unrealized
542
+ active_pnl_color = "#00ff00" if pnl_val_unrealized >= 0 else "#ff0000"
 
543
  portfolio = await r2.get_portfolio_state_async()
544
  total_t = portfolio.get('total_trades', 0)
545
  wins = portfolio.get('winning_trades', 0)
 
549
  tot_loss = portfolio.get('total_loss_usd', 0.0)
550
  net_prof = tot_prof - tot_loss
551
  win_rate = (wins / total_t * 100) if total_t > 0 else 0.0
 
552
  halt_status = "<span style='color:red; font-weight:bold;'>HALTED</span>" if is_halted else "<span style='color:#00ff00;'>ACTIVE</span>"
 
553
 
554
  wallet_md = f"""
555
  <div style='background-color: #1a1a1a; padding: 15px; border-radius: 8px; border: 1px solid #333; text-align:center;'>
556
  <h3 style='margin:0; color:#888; font-size:14px;'>💼 Institutional Portfolio</h3>
557
  <div style='font-size: 24px; font-weight: bold; color: white; margin: 5px 0 0 0;'>${virtual_equity:,.2f}</div>
558
+ <div style='font-size: 14px; color: {active_pnl_color}; margin-bottom: 5px;'>({pnl_val_unrealized:+,.2f} USD)</div>
559
 
560
  <table style='width:100%; font-size:12px; margin-top:5px; color:#ccc;'>
561
  <tr><td>Allocated:</td><td style='text-align:right; color:#ffa500;'>${allocated:.2f}</td></tr>
562
  <tr><td>Free Cap:</td><td style='text-align:right; color:#00ff00;'>${free_cap:.2f}</td></tr>
563
+ <tr><td>Daily PnL:</td><td style='text-align:right; color:{"#00ff00" if daily_pnl>=0 else "#ff0000"};'>${daily_pnl:+.2f}</td></tr>
564
  </table>
565
 
566
  <hr style='border-color:#444; margin: 10px 0;'>
567
 
568
  <div style='display: flex; justify-content: space-between; font-size: 12px; color: #ccc;'>
569
+ <span>🦅 Mood:</span> <span style='color: white;'>{sp.market_trend}</span>
 
 
 
570
  </div>
571
  <div style='display: flex; justify-content: space-between; font-size: 12px; color: #ccc; margin-top:5px;'>
572
  <span>🛡️ Status:</span> {halt_status}
 
575
  </div>
576
  """
577
 
578
+ # Guardian Stats
579
  key_map = {
580
  "Dual-Core (Hybrid)": "hybrid",
581
  "Hydra: Crash (Panic)": "crash",
 
583
  "Hydra: Stagnation (Time)": "stagnation"
584
  }
585
  target_key = key_map.get(selected_view, "hybrid")
 
586
  stats_data = trade_manager.ai_stats.get(target_key, {"total":0, "good":0, "saved":0.0, "missed":0.0})
587
 
588
  tot_ds = stats_data['total']
 
604
  <tr><td>Interventions:</td><td style='text-align:right;'>{tot_ds}</td></tr>
605
  <tr><td>Accuracy:</td><td style='text-align:right; color:#00e5ff;'>{ds_acc:.1f}%</td></tr>
606
  <tr><td>Saved:</td><td style='text-align:right; color:#00ff00;'>${stats_data['saved']:.2f}</td></tr>
 
607
  </table>
608
  </div>
609
  """
 
612
  if adaptive_hub:
613
  if hasattr(adaptive_hub, 'get_learning_progress'):
614
  fast_learn_prog = adaptive_hub.get_learning_progress()
 
 
 
 
 
 
615
 
616
+ metrics = scheduler.get_status_metrics() if scheduler else {}
617
+ sch_w_time = metrics.get("weekly_timer", "Wait")
618
+ sch_w_cnt = metrics.get("weekly_count", 0)
 
 
 
 
 
 
619
 
620
  neural_md = f"""
621
  <div style='background-color: #1a1a1a; padding: 10px; border-radius: 8px; border: 1px solid #333; font-size: 12px; margin-top: 10px;'>
622
+ <h3 style='margin:0; color:#00e5ff; font-size:14px;'>🧠 Neural Cycles</h3>
 
 
 
623
  <table style='width:100%; color:#ccc;'>
624
  <tr style='border-bottom: 1px solid #333;'>
625
  <td style='padding:4px 0;'>⚡ Fast Learner:</td>
626
  <td style='text-align:right; color:#ffff00; font-weight:bold;'>{fast_learn_prog}</td>
 
627
  </tr>
628
  <tr style='border-bottom: 1px solid #333;'>
629
  <td style='padding:4px 0;'>📅 Weekly Tune:</td>
630
  <td style='text-align:right; color:#fff;'>{sch_w_time}</td>
 
 
 
 
 
 
631
  </tr>
632
  </table>
 
 
 
633
  </div>
634
  """
635
 
636
+ # Diagnostic Matrix
637
  diag_data = await r2.get_diagnostic_stats_async()
638
  diag_list = []
639
+ ordered_models = ["Titan", "Patterns", "Oracle", "Sniper", "MonteCarlo_L", "Governance"]
640
 
641
  for m in ordered_models:
642
  stats = diag_data.get(m, {"wins": 0, "losses": 0, "pnl": 0.0})
643
  pnl_val = stats['pnl']
 
 
644
  color = "#00ff00" if pnl_val >= 0 else "#ff0000"
645
  pnl_str = f"<span style='color: {color}; font-weight: bold;'>${pnl_val:+.2f}</span>"
646
+ diag_list.append([m, stats['wins'], stats['losses'], pnl_str])
 
 
 
 
 
 
647
 
648
  diag_df = pd.DataFrame(diag_list, columns=["Model", "Wins", "Losses", "PnL (USD)"])
649
 
650
+ # ✅ NEW: Type Stats DataFrame
651
+ type_stats_list = []
652
+ if trade_manager and hasattr(trade_manager, 'type_stats'):
653
+ for t_name, t_data in trade_manager.type_stats.items():
654
+ name_clean = t_name.replace("_", " ")
655
+ wins = t_data.get('wins', 0)
656
+ losses = t_data.get('losses', 0)
657
+ prof = t_data.get('profit_usd', 0.0)
658
+ loss_val = t_data.get('loss_usd', 0.0)
659
+
660
+ # Format: +$Profit / -$Loss
661
+ profitability_html = format_pnl_split(prof, loss_val)
662
+ type_stats_list.append([name_clean, wins, losses, profitability_html])
663
+
664
+ type_df = pd.DataFrame(type_stats_list, columns=["Coin Type", "Wins", "Losses", "Profitability"])
665
+
666
  wl_data = [[k, f"{v.get('final_total_score',0):.2f}"] for k, v in trade_manager.watchlist.items()]
667
  wl_df = pd.DataFrame(wl_data, columns=["Coin", "Score"])
668
 
 
682
  if entry_p > 0:
683
  fig.add_hline(y=entry_p, line_dash="dash", line_color="white", annotation_text="ENTRY", annotation_position="top left")
684
  if tp_p > 0:
685
+ fig.add_hline(y=tp_p, line_color="#00ff00", line_width=2, annotation_text="TP", annotation_position="top left")
686
  if sl_p > 0:
687
+ fig.add_hline(y=sl_p, line_color="#ff0000", line_width=2, annotation_text="SL", annotation_position="bottom left")
688
 
689
  fig.update_layout(
690
  template="plotly_dark",
 
693
  margin=dict(l=0, r=40, t=30, b=0),
694
  height=400,
695
  xaxis_rangeslider_visible=False,
696
+ title=dict(text=f"{symbol} (Long) | PnL: {pnl_pct:+.2f}%", font=dict(color="white"))
697
  )
698
 
699
  train_status = sys_state.training_status_msg
700
  if sys_state.training_running: train_status = "🧪 Backtest Running..."
701
 
 
702
  return (status_txt, status_line, fig, f"{curr_p:.6f}", f"{entry_p:.6f}", f"{tp_p:.6f}", f"{sl_p:.6f}",
703
+ f"{pnl_pct:+.2f}%", wl_df, diag_df, type_df, wallet_md, history_md, neural_md)
704
 
705
  except Exception:
706
  traceback.print_exc()
707
+ return "Error", "Error", empty_chart, "0", "0", "0", "0", "0%", wl_df_empty, diag_df_empty, type_df_empty, "Err", "Err", "Err"
708
 
709
  # ------------------------------------------------------------------------------
710
  # Gradio UI Construction
 
712
  def create_gradio_ui():
713
  custom_css = ".gradio-container {background:#0b0f19} .dataframe {background:#1a1a1a!important} .html-box {min-height:180px}"
714
 
715
+ with gr.Blocks(title="Titan V61.0 (Dual-Type Dashboard)") as demo:
716
  gr.HTML(f"<style>{custom_css}</style>")
717
 
718
+ gr.Markdown("# 🚀 Titan V61.0 (Cybernetic: Dual-Type Engine)")
719
 
720
  with gr.Row():
721
  with gr.Column(scale=3):
 
732
  wallet_out = gr.HTML(label="Smart Wallet", elem_classes="html-box")
733
  neural_out = gr.HTML(label="Neural Cycles", elem_classes="html-box")
734
 
735
+ # NEW: Type Stats Table
736
+ gr.Markdown("### 💎 Opportunity Types")
737
+ type_stats_out = gr.Dataframe(
738
+ headers=["Coin Type", "Wins", "Losses", "Profitability"],
739
+ datatype=["str", "number", "number", "html"],
740
+ interactive=False,
741
+ label="Type Performance"
742
+ )
743
+
744
  gr.Markdown("### 🕵️ Diagnostic Matrix")
745
  diagnostic_out = gr.Dataframe(
746
  headers=["Model", "Wins", "Losses", "PnL (USD)"],
747
+ datatype=["str", "number", "number", "html"],
748
  interactive=False,
749
  label="Model Performance"
750
  )
 
786
  logs = gr.Textbox(label="Logs", lines=14, autoscroll=True, elem_classes="log-box", type="text")
787
  gr.HTML("<style>.log-box textarea { font-family: 'Consolas', 'Monaco', monospace !important; font-size: 12px !important; white-space: pre !important; }</style>")
788
 
 
789
  btn_run.click(fn=run_cycle_from_gradio, outputs=alert)
790
  btn_close.click(fn=manual_close_current_trade, outputs=alert)
791
  btn_history_reset.click(fn=reset_history_handler, outputs=alert)
 
794
  btn_backtest.click(fn=trigger_strategic_backtest, outputs=alert)
795
  auto_pilot.change(fn=toggle_auto_pilot, inputs=auto_pilot, outputs=alert)
796
 
 
797
  btn_reset_diag.click(fn=reset_diagnostics_handler, outputs=alert)
798
  btn_reset_guard.click(fn=reset_guardians_handler, outputs=alert)
799
 
800
+ # Added type_stats_out to outputs
801
  gr.Timer(3).tick(fn=check_live_pnl_and_status, inputs=stats_dd,
802
+ outputs=[logs, status, live_chart, t_price, t_entry, t_tp, t_sl, t_pnl, watchlist_out, diagnostic_out, type_stats_out, wallet_out, history_out, neural_out])
803
  return demo
804
 
805
  fast_api_server = FastAPI(lifespan=lifespan)