Riy777 commited on
Commit
b39d9b5
Β·
verified Β·
1 Parent(s): f9f853e

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +168 -163
app.py CHANGED
@@ -1,10 +1,9 @@
1
  # ==============================================================================
2
- # πŸš€ app.py (V69.0 - GEM-Architect: Full Scale Production System)
3
  # ==============================================================================
4
- # - Architecture: Titan V2 (ResNet) + Oracle V4.5 (LightGBM Exp.Ret).
5
- # - Removed: Legacy Pattern Engine columns and logic.
6
- # - Integrates: R2, Whale Monitor, News, Sentiment, Adaptive Hub, Tuner.
7
- # - UI: Full Gradio Dashboard with Charting, Logging, and Manual Controls.
8
  # ==============================================================================
9
 
10
  import os
@@ -109,7 +108,7 @@ class SystemState:
109
 
110
  def set_ready(self):
111
  self.ready = True
112
- self.last_cycle_logs = "βœ… System Ready. Titan V2 (Pure ResNet) Online."
113
  logger.info("βœ… System State set to READY.")
114
 
115
  def set_cycle_start(self):
@@ -207,7 +206,7 @@ async def auto_pilot_loop():
207
  async def lifespan(app: FastAPI):
208
  global r2, data_manager, ml_processor, adaptive_hub, trade_manager, whale_monitor, news_fetcher, senti_analyzer, sys_state
209
 
210
- logger.info("\nπŸš€ [System] Startup Sequence (Titan V69.0 - Production)...")
211
  try:
212
  # 1. Initialize R2 (Persistence)
213
  r2 = R2Service()
@@ -231,7 +230,7 @@ async def lifespan(app: FastAPI):
231
  adaptive_hub = AdaptiveHub(r2_service=r2)
232
  await adaptive_hub.initialize()
233
 
234
- # 6. Initialize ML Processor (Titan V2 + Oracle)
235
  ml_processor = MLProcessor(data_manager=data_manager)
236
  await ml_processor.initialize()
237
 
@@ -268,16 +267,16 @@ async def lifespan(app: FastAPI):
268
  logger.info("βœ… [System] Shutdown Complete.")
269
 
270
  # ------------------------------------------------------------------------------
271
- # 7. Analysis Tasks (Layer 2)
272
  # ------------------------------------------------------------------------------
273
- async def _analyze_symbol_task(candidate_data: Dict[str, Any]) -> Dict[str, Any]:
274
  """
275
- Performs deep L2 analysis on a single symbol using MLProcessor.
276
- Fetches required 5m, 15m, 1h, 4h data.
277
  """
278
  try:
279
  symbol = candidate_data['symbol']
280
- required_tfs = ["5m", "15m", "1h", "4h"]
281
 
282
  # Concurrent Data Fetching
283
  data_tasks = [data_manager.get_latest_ohlcv(symbol, tf, limit=300) for tf in required_tfs]
@@ -288,7 +287,7 @@ async def _analyze_symbol_task(candidate_data: Dict[str, Any]) -> Dict[str, Any]
288
  if data and len(data) > 0: ohlcv_data[tf] = data
289
 
290
  # Validation: Ensure critical timeframes exist
291
- if '1h' not in ohlcv_data or '5m' not in ohlcv_data:
292
  return None
293
 
294
  current_price = await data_manager.get_latest_price_async(symbol)
@@ -305,24 +304,22 @@ async def _analyze_symbol_task(candidate_data: Dict[str, Any]) -> Dict[str, Any]
305
  'strategy_type': candidate_data.get('strategy_type', 'NORMAL'),
306
  'l1_score': candidate_data.get('l1_sort_score', 0)
307
  }
308
-
309
- # Call Processor (Titan V2 -> Oracle)
310
- res = await ml_processor.process_compound_signal(raw_data)
311
- if not res: return None
312
-
313
- # Pass through strategy type
314
- res['strategy_type'] = candidate_data.get('strategy_type', 'NORMAL')
315
- return res
316
  except Exception:
317
  return None
318
 
319
  # ------------------------------------------------------------------------------
320
- # 8. Unified Logic Cycle (The Core Loop)
321
  # ------------------------------------------------------------------------------
322
  async def run_unified_cycle():
323
  """
324
- Executes the full L1 -> L2 -> L3 -> L4 Analysis Pipeline.
325
- Updated for Titan V2 (No Patterns logic).
 
 
 
 
326
  """
327
  log_buffer = StringIO()
328
  def log_and_print(message):
@@ -347,160 +344,158 @@ async def run_unified_cycle():
347
  pnl = ((curr_p - entry_p) / entry_p) * 100 if entry_p > 0 else 0
348
  log_and_print(f" πŸ”’ {sym}: {pnl:+.2f}%")
349
 
350
- # --- PHASE 1: L1 Screening ---
351
- log_and_print(f" [1/5] πŸ” L1 Screening (Bottom/Momentum)...")
352
- candidates = await data_manager.layer1_rapid_screening(adaptive_hub_ref=adaptive_hub)
353
- if not candidates:
354
- log_and_print("⚠️ No valid candidates found (Quality Filter).")
 
 
 
355
  sys_state.set_cycle_end(logs=log_buffer.getvalue())
356
  return
357
 
358
- # --- PHASE 2: L2 Deep Analysis ---
359
- log_and_print(f" [2/5] 🧠 L2 Deep Analysis ({len(candidates)} items)...")
360
- tasks = [_analyze_symbol_task(c) for c in candidates]
361
- results = await asyncio.gather(*tasks)
362
-
363
- # Filter Results
364
- valid_l2 = [res for res in results if res is not None and res.get('is_valid', False)]
365
- rejected_l2 = [res for res in results if res is not None and not res.get('is_valid', False)]
366
-
367
- rejected_l2.sort(key=lambda x: x.get('enhanced_final_score', 0.0), reverse=True)
368
-
369
- if not valid_l2:
370
- log_and_print("⚠️ No valid L2 candidates (Hard Gates Active). Top Rejected:")
371
- # Updated Rejection Header (Removed Patterns)
372
- rej_header = f"{'SYM':<9} | {'TITAN':<5} | {'MC':<5} | {'FINAL':<5} | {'REASON'}"
373
- log_and_print(rej_header)
374
- log_and_print("-" * 100)
375
-
376
- for rej in rejected_l2[:10]:
377
- sym = rej['symbol']
378
- tit = rej.get('titan_score', 0.0)
379
- mc = rej.get('mc_score', 0.0)
380
- fin = rej.get('enhanced_final_score', 0.0)
381
- reason = rej.get('rejection_reason', 'Unknown')
382
- log_and_print(f"{sym:<9} | {tit:.1f} | {mc:.1f} | {fin:.1f} | {reason}")
383
-
384
  sys_state.set_cycle_end(logs=log_buffer.getvalue())
385
  return
386
 
387
- # Select Top Semi-Finalists
388
- semi_finalists = sorted(valid_l2, key=lambda x: x.get('enhanced_final_score', 0.0), reverse=True)[:10]
389
-
390
- # --- PHASE 3: L3 Deep Dive (Context & Oracle) ---
391
- log_and_print(f" [3/5] πŸ“‘ L3 Deep Dive (Whales/News) & Oracle Check...")
392
- final_candidates = []
393
-
394
- for sig in semi_finalists:
395
- symbol = sig['symbol']
396
- l2_score = sig.get('enhanced_final_score', 0.0)
 
 
 
 
 
397
 
398
  # Whale Analysis
399
- whale_points = 0.0
400
- try:
401
- if whale_monitor:
402
- w_data = await whale_monitor.get_symbol_whale_activity(symbol, known_price=sig.get('current_price', 0))
403
- if w_data and w_data.get('data_available', False) and 'trading_signal' in w_data:
404
- signal = w_data['trading_signal']
405
- action = signal.get('action', 'HOLD')
406
- confidence = float(signal.get('confidence', 0.5))
407
- dynamic_impact = SystemLimits.L3_WHALE_IMPACT_MAX * confidence
408
- if action == 'BUY': whale_points = dynamic_impact
409
- elif action == 'SELL': whale_points = -dynamic_impact
410
- except Exception: pass
411
 
412
  # News Analysis
413
- news_points = 0.0
414
- try:
415
- if news_fetcher and senti_analyzer:
416
  n_data = await news_fetcher.get_news(symbol)
417
- summary_text = n_data.get('summary', '')
418
- if "No specific news" not in summary_text:
419
- sent = senti_analyzer.polarity_scores(summary_text)
420
- compound_score = sent['compound']
421
- news_points = compound_score * SystemLimits.L3_NEWS_IMPACT_MAX
422
- except Exception: pass
423
-
424
- # Advanced MC (Placeholder for future expansion)
425
- mc_a_points = 0.0
426
- try:
427
- raw_mc_a = await ml_processor.run_advanced_monte_carlo(symbol, '1h')
428
- mc_a_points = max(-SystemLimits.L3_MC_ADVANCED_MAX, min(SystemLimits.L3_MC_ADVANCED_MAX, raw_mc_a))
429
- except Exception: pass
430
-
431
- # Calculate Final Score (Pre-Oracle)
432
- final_score = l2_score + whale_points + news_points + mc_a_points
433
 
434
- sig['whale_score'] = whale_points
435
- sig['news_score'] = news_points
436
- sig['mc_advanced_score'] = mc_a_points
437
- sig['final_total_score'] = final_score
438
- final_candidates.append(sig)
 
 
 
 
 
 
 
 
 
439
 
440
- final_candidates.sort(key=lambda x: x['final_total_score'], reverse=True)
 
441
 
442
- approved_signals = []
 
 
 
443
 
444
- # βœ… UPDATED HEADER: Showing Oracle PnL (Exp.Ret) instead of Patterns
445
- header = (f"{'SYM':<9} | {'TYPE':<8} | {'TITAN':<5} | {'MC':<4} | "
446
- f"{'NEWS':<5} | {'WHALE':<6} | {'FINAL':<6} | {'EXP.RET':<8} | {'STATUS'}")
447
-
448
- log_and_print("-" * 140)
449
- log_and_print(header)
450
- log_and_print("-" * 140)
451
 
452
- for sig in final_candidates:
453
- symbol = sig['symbol']
 
454
 
455
- # Consult Updated Oracle
456
- decision = await ml_processor.consult_oracle(sig)
 
457
 
458
- action = decision.get('action', 'WAIT')
459
- oracle_score = decision.get('oracle_score', 0.0) # Expected PnL from LightGBM
460
- target_class = decision.get('target_class', '')
461
 
462
- status_str = "WAIT πŸ”΄"
463
- # If Oracle says Watch or Buy, we approve for Governance
464
- if action == 'WATCH' or action == 'BUY':
465
- status_str = f"βœ… {target_class}"
466
- sig.update(decision)
467
- approved_signals.append(sig)
468
-
469
- titan_d = sig.get('titan_score', 0.0)
470
- news_d = sig.get('news_score', 0.0)
471
- whale_d = sig.get('whale_score', 0.0)
472
- mc_d = sig.get('mc_score', 0.0)
473
- final_d = sig.get('final_total_score', 0.0)
474
- strat_type = sig.get('strategy_type', 'N/A')
475
-
476
- log_and_print(
477
- f"{symbol:<9} | "
478
- f"{strat_type:<8} | "
479
- f"{titan_d:.1f} | "
480
- f"{mc_d:.1f} | "
481
- f"{news_d:+.1f} | "
482
- f"{whale_d:+.1f} | "
483
- f"{final_d:.1f} | "
484
- f"{oracle_score*100:+.2f}% | " # Display Expected Return
485
- f"{status_str}"
486
- )
487
-
488
- # --- PHASE 4: Execution & Governance ---
489
- if approved_signals:
490
- log_and_print("-" * 140)
491
- log_and_print(f" [4/5] 🎯 L4 Sniper -> πŸ›οΈ Governance -> πŸ’° Portfolio ({len(approved_signals)} candidates)...")
492
- tm_log_buffer = StringIO()
493
 
494
- # Capture Trade Manager Output
495
- with redirect_stdout(tm_log_buffer), redirect_stderr(tm_log_buffer):
496
- await trade_manager.select_and_execute_best_signal(approved_signals)
497
 
498
- tm_logs = tm_log_buffer.getvalue()
499
- for line in tm_logs.splitlines():
500
- if line.strip(): log_and_print(line.strip())
501
- else:
502
- log_and_print(" -> πŸ›‘ No candidates passed Oracle's Golden Threshold.")
 
 
 
 
 
 
 
 
503
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
504
  gc.collect()
505
  sys_state.set_cycle_end(logs=log_buffer.getvalue())
506
 
@@ -633,7 +628,7 @@ async def check_live_pnl_and_status(selected_view="Dual-Core (Hybrid)"):
633
  decision_data = trade.get('decision_data', {})
634
  gov_grade = decision_data.get('governance_grade', 'N/A')
635
  gov_score = decision_data.get('governance_score', 0.0)
636
- oracle_score = decision_data.get('oracle_score', 0.0) # New Metric
637
 
638
  grade_color = "#ccc"
639
  if gov_grade == "ULTRA": grade_color = "#ff00ff"
@@ -756,11 +751,17 @@ async def check_live_pnl_and_status(selected_view="Dual-Core (Hybrid)"):
756
  # --- DataFrames ---
757
  diag_data = await r2.get_diagnostic_stats_async()
758
  diag_list = []
759
- # Removed Patterns
760
- ordered_models = ["Titan", "Oracle", "Sniper", "MonteCarlo_L", "MonteCarlo_A", "News", "Governance"]
761
 
762
  for m in ordered_models:
763
  stats = diag_data.get(m, {"wins": 0, "losses": 0, "pnl": 0.0, "profit_accum": 0.0, "loss_accum": 0.0})
 
 
 
 
 
 
764
  profit_accum = stats.get('profit_accum', 0.0)
765
  loss_accum = stats.get('loss_accum', 0.0)
766
  if profit_accum == 0.0 and loss_accum == 0.0 and stats['pnl'] != 0.0:
@@ -768,7 +769,11 @@ async def check_live_pnl_and_status(selected_view="Dual-Core (Hybrid)"):
768
  else: loss_accum = abs(stats['pnl'])
769
 
770
  pnl_str = format_pnl_split(profit_accum, loss_accum)
771
- diag_list.append([m, stats['wins'], stats['losses'], pnl_str])
 
 
 
 
772
 
773
  diag_df = pd.DataFrame(diag_list, columns=["Model", "Wins", "Losses", "PnL (USD)"])
774
 
@@ -835,9 +840,9 @@ async def check_live_pnl_and_status(selected_view="Dual-Core (Hybrid)"):
835
  def create_gradio_ui():
836
  custom_css = ".gradio-container {background:#0b0f19} .dataframe {background:#1a1a1a!important} .html-box {min-height:180px}"
837
 
838
- with gr.Blocks(title="Titan V69.0 (Integrated)", css=custom_css) as demo:
839
 
840
- gr.Markdown("# πŸš€ Titan V69.0 (Pure Titan + Oracle V4.5)")
841
 
842
  with gr.Row():
843
  # LEFT: Chart & Controls
 
1
  # ==============================================================================
2
+ # πŸš€ app.py (V70.0 - GEM-Architect: The 5-Layer Neural Core)
3
  # ==============================================================================
4
+ # - Architecture: PatternNet (ResNet) + Oracle V4.5 + Sniper V2.
5
+ # - Logic: 5-Stage Precision Funnel (Breadth -> Neural -> External -> Micro -> Governance).
6
+ # - UI: Full Gradio Dashboard with Real-time Monitoring.
 
7
  # ==============================================================================
8
 
9
  import os
 
108
 
109
  def set_ready(self):
110
  self.ready = True
111
+ self.last_cycle_logs = "βœ… System Ready. PatternNet (ResNet) Online."
112
  logger.info("βœ… System State set to READY.")
113
 
114
  def set_cycle_start(self):
 
206
  async def lifespan(app: FastAPI):
207
  global r2, data_manager, ml_processor, adaptive_hub, trade_manager, whale_monitor, news_fetcher, senti_analyzer, sys_state
208
 
209
+ logger.info("\nπŸš€ [System] Startup Sequence (Titan V70.0 - 5-Layer Core)...")
210
  try:
211
  # 1. Initialize R2 (Persistence)
212
  r2 = R2Service()
 
230
  adaptive_hub = AdaptiveHub(r2_service=r2)
231
  await adaptive_hub.initialize()
232
 
233
+ # 6. Initialize ML Processor (PatternNet + Oracle + Sniper)
234
  ml_processor = MLProcessor(data_manager=data_manager)
235
  await ml_processor.initialize()
236
 
 
267
  logger.info("βœ… [System] Shutdown Complete.")
268
 
269
  # ------------------------------------------------------------------------------
270
+ # 7. Analysis Tasks (Data Fetcher for Layers)
271
  # ------------------------------------------------------------------------------
272
+ async def _fetch_l2_data_task(candidate_data: Dict[str, Any]) -> Dict[str, Any]:
273
  """
274
+ Fetches required 15m, 1h, 4h data for L2 (Pattern/Oracle/MC).
275
+ Does NOT run the models, just prepares the data package.
276
  """
277
  try:
278
  symbol = candidate_data['symbol']
279
+ required_tfs = ["15m", "1h", "4h"] # PatternNet needs 15m, MC needs 1h
280
 
281
  # Concurrent Data Fetching
282
  data_tasks = [data_manager.get_latest_ohlcv(symbol, tf, limit=300) for tf in required_tfs]
 
287
  if data and len(data) > 0: ohlcv_data[tf] = data
288
 
289
  # Validation: Ensure critical timeframes exist
290
+ if '15m' not in ohlcv_data:
291
  return None
292
 
293
  current_price = await data_manager.get_latest_price_async(symbol)
 
304
  'strategy_type': candidate_data.get('strategy_type', 'NORMAL'),
305
  'l1_score': candidate_data.get('l1_sort_score', 0)
306
  }
307
+ return raw_data
308
+
 
 
 
 
 
 
309
  except Exception:
310
  return None
311
 
312
  # ------------------------------------------------------------------------------
313
+ # 8. Unified Logic Cycle (The 5-Layer Pipeline)
314
  # ------------------------------------------------------------------------------
315
  async def run_unified_cycle():
316
  """
317
+ πŸ’Ž GEM-Architect: The 5-Layer Precision Pipeline
318
+ Layer 1: Breadth Filter (Data Manager)
319
+ Layer 2: Pattern + Oracle + MC (Score & Gate) -> Limit to Top 10
320
+ Layer 3: External Data (News + Whales) -> Re-Rank Top 10
321
+ Layer 4: Sniper (Micro-Structure) -> Pick Best 1
322
+ Layer 5: Governance (Senate) -> Final Approval & Execution
323
  """
324
  log_buffer = StringIO()
325
  def log_and_print(message):
 
344
  pnl = ((curr_p - entry_p) / entry_p) * 100 if entry_p > 0 else 0
345
  log_and_print(f" πŸ”’ {sym}: {pnl:+.2f}%")
346
 
347
+ # ==============================================================================
348
+ # 🌊 LAYER 1: Market Breadth & Liquidity Filter
349
+ # ==============================================================================
350
+ log_and_print(f" [1/5] 🌊 Layer 1: Market Breadth & Liquidity Screen...")
351
+ l1_candidates = await data_manager.layer1_rapid_screening(limit=200, adaptive_hub_ref=adaptive_hub)
352
+
353
+ if not l1_candidates:
354
+ log_and_print("⚠️ [Layer 1] No candidates found (Market unsafe or flat).")
355
  sys_state.set_cycle_end(logs=log_buffer.getvalue())
356
  return
357
 
358
+ # ==============================================================================
359
+ # 🧠 LAYER 2: Neural Analysis (PatternNet + Oracle + MC)
360
+ # ==============================================================================
361
+ log_and_print(f" [2/5] 🧠 Layer 2: Neural Pattern Analysis ({len(l1_candidates)} coins)...")
362
+
363
+ # Helper wrapper for concurrency
364
+ async def process_l2(cand):
365
+ raw_data = await _fetch_l2_data_task(cand)
366
+ if not raw_data: return None
367
+ return await ml_processor.execute_layer2_analysis(raw_data)
368
+
369
+ # Batch execute L2
370
+ l2_tasks = [process_l2(c) for c in l1_candidates]
371
+ l2_results = await asyncio.gather(*l2_tasks)
372
+
373
+ # Filter failures (None)
374
+ valid_l2 = [res for res in l2_results if res is not None]
375
+
376
+ # Sort by Composite Score and Keep TOP 10
377
+ valid_l2.sort(key=lambda x: x['l2_score'], reverse=True)
378
+ top_10_candidates = valid_l2[:10]
379
+
380
+ if not top_10_candidates:
381
+ log_and_print("⚠️ [Layer 2] All candidates failed Pattern Gate (<40%).")
382
+ # Log top rejected for debug
 
383
  sys_state.set_cycle_end(logs=log_buffer.getvalue())
384
  return
385
 
386
+ # ==============================================================================
387
+ # πŸ“‘ LAYER 3: External Intelligence (News + Whales)
388
+ # ==============================================================================
389
+ log_and_print(f" [3/5] πŸ“‘ Layer 3: External Intelligence Injection (Top {len(top_10_candidates)})...")
390
+ final_l3_list = []
391
+
392
+ # Header for L3 Table
393
+ header = (f"{'SYM':<9} | {'PATT':<5} | {'MC':<4} | {'ORCL':<5} | "
394
+ f"{'WHALE':<5} | {'NEWS':<5} | {'TOTAL':<6}")
395
+ log_and_print("-" * 60)
396
+ log_and_print(header)
397
+
398
+ for cand in top_10_candidates:
399
+ symbol = cand['symbol']
400
+ l2_score = cand['l2_score']
401
 
402
  # Whale Analysis
403
+ whale_bonus = 0.0
404
+ if whale_monitor:
405
+ try:
406
+ w_data = await whale_monitor.get_symbol_whale_activity(symbol, known_price=cand.get('current_price', 0))
407
+ if w_data and w_data.get('trading_signal', {}).get('action') == 'BUY':
408
+ conf = float(w_data.get('trading_signal', {}).get('confidence', 0.5))
409
+ whale_bonus = SystemLimits.L3_WHALE_IMPACT_MAX * conf
410
+ except: pass
 
 
 
 
411
 
412
  # News Analysis
413
+ news_bonus = 0.0
414
+ if news_fetcher and senti_analyzer:
415
+ try:
416
  n_data = await news_fetcher.get_news(symbol)
417
+ summary = n_data.get('summary', '')
418
+ if "No specific news" not in summary:
419
+ sent = senti_analyzer.polarity_scores(summary)
420
+ news_bonus = sent['compound'] * SystemLimits.L3_NEWS_IMPACT_MAX
421
+ except: pass
422
+
423
+ # Final Score Calculation
424
+ final_score = l2_score + whale_bonus + news_bonus
 
 
 
 
 
 
 
 
425
 
426
+ cand['whale_score'] = whale_bonus
427
+ cand['news_score'] = news_bonus
428
+ cand['final_total_score'] = final_score
429
+
430
+ log_and_print(
431
+ f"{symbol:<9} | "
432
+ f"{cand['pattern_score']*100:.1f} | "
433
+ f"{cand['mc_score']*100:.1f} | "
434
+ f"{cand['oracle_score']*100:.1f} | "
435
+ f"{whale_bonus:+.1f} | "
436
+ f"{news_bonus:+.1f} | "
437
+ f"{final_score:.1f}"
438
+ )
439
+ final_l3_list.append(cand)
440
 
441
+ # Re-sort based on L3 Total
442
+ final_l3_list.sort(key=lambda x: x['final_total_score'], reverse=True)
443
 
444
+ # ==============================================================================
445
+ # 🎯 LAYER 4: Sniper (Micro-Structure) - Find The One
446
+ # ==============================================================================
447
+ log_and_print(f" [4/5] 🎯 Layer 4: Sniper Micro-Analysis (Scanning Top 5)...")
448
 
449
+ best_candidate = None
450
+ best_sniper_score = -1.0
 
 
 
 
 
451
 
452
+ # Scan top 5 only to save API/Processing
453
+ for cand in final_l3_list[:5]:
454
+ symbol = cand['symbol']
455
 
456
+ # Fetch 1m Data & Order Book
457
+ t1m = await data_manager.get_latest_ohlcv(symbol, '1m', 500)
458
+ ob = await data_manager.get_order_book_snapshot(symbol)
459
 
460
+ if not t1m or not ob: continue
 
 
461
 
462
+ # Run Sniper
463
+ sniper_res = await ml_processor.execute_layer4_sniper(symbol, t1m, ob)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
464
 
465
+ s_sig = sniper_res.get('signal', 'WAIT')
466
+ s_conf = sniper_res.get('confidence_prob', 0.0)
467
+ s_reason = sniper_res.get('reason', 'N/A')
468
 
469
+ log_and_print(f" πŸ”­ {symbol:<6} -> Signal: {s_sig} | Conf: {s_conf:.2f} | {s_reason}")
470
+
471
+ # Logic: Must be BUY and have highest score
472
+ if s_sig == 'BUY' and s_conf > best_sniper_score:
473
+ best_sniper_score = s_conf
474
+ cand['sniper_entry_price'] = sniper_res.get('entry_price', 0)
475
+ cand['sniper_score'] = s_conf
476
+ best_candidate = cand
477
+
478
+ if not best_candidate:
479
+ log_and_print("πŸ›‘ Layer 4: Sniper found no valid entry points in top candidates.")
480
+ sys_state.set_cycle_end(logs=log_buffer.getvalue())
481
+ return
482
 
483
+ # ==============================================================================
484
+ # πŸ›οΈ LAYER 5: Governance & Execution
485
+ # ==============================================================================
486
+ log_and_print(f" [5/5] πŸ›οΈ Layer 5: Sending {best_candidate['symbol']} to Governance...")
487
+
488
+ tm_log_buffer = StringIO()
489
+
490
+ # Capture Trade Manager Output
491
+ with redirect_stdout(tm_log_buffer), redirect_stderr(tm_log_buffer):
492
+ # Pass as a list because TM expects a list of candidates to confirm
493
+ await trade_manager.select_and_execute_best_signal([best_candidate])
494
+
495
+ tm_logs = tm_log_buffer.getvalue()
496
+ for line in tm_logs.splitlines():
497
+ if line.strip(): log_and_print(line.strip())
498
+
499
  gc.collect()
500
  sys_state.set_cycle_end(logs=log_buffer.getvalue())
501
 
 
628
  decision_data = trade.get('decision_data', {})
629
  gov_grade = decision_data.get('governance_grade', 'N/A')
630
  gov_score = decision_data.get('governance_score', 0.0)
631
+ oracle_score = decision_data.get('oracle_score', 0.0)
632
 
633
  grade_color = "#ccc"
634
  if gov_grade == "ULTRA": grade_color = "#ff00ff"
 
751
  # --- DataFrames ---
752
  diag_data = await r2.get_diagnostic_stats_async()
753
  diag_list = []
754
+ # Updated Keys: Titan -> Pattern (Backwards compatibility logic)
755
+ ordered_models = ["Titan", "Pattern", "Oracle", "Sniper", "MonteCarlo_L", "MonteCarlo_A", "News", "Governance"]
756
 
757
  for m in ordered_models:
758
  stats = diag_data.get(m, {"wins": 0, "losses": 0, "pnl": 0.0, "profit_accum": 0.0, "loss_accum": 0.0})
759
+
760
+ # Merge Titan & Pattern stats if needed
761
+ if m == "Pattern" and "Titan" in diag_data:
762
+ # Optional: You can choose to display them separate or merged
763
+ pass
764
+
765
  profit_accum = stats.get('profit_accum', 0.0)
766
  loss_accum = stats.get('loss_accum', 0.0)
767
  if profit_accum == 0.0 and loss_accum == 0.0 and stats['pnl'] != 0.0:
 
769
  else: loss_accum = abs(stats['pnl'])
770
 
771
  pnl_str = format_pnl_split(profit_accum, loss_accum)
772
+ # Rename Titan to Pattern in UI if found
773
+ display_name = "Pattern (Net)" if m == "Titan" else m
774
+
775
+ if stats['wins'] + stats['losses'] > 0:
776
+ diag_list.append([display_name, stats['wins'], stats['losses'], pnl_str])
777
 
778
  diag_df = pd.DataFrame(diag_list, columns=["Model", "Wins", "Losses", "PnL (USD)"])
779
 
 
840
  def create_gradio_ui():
841
  custom_css = ".gradio-container {background:#0b0f19} .dataframe {background:#1a1a1a!important} .html-box {min-height:180px}"
842
 
843
+ with gr.Blocks(title="Titan V70.0 (5-Layer Core)", css=custom_css) as demo:
844
 
845
+ gr.Markdown("# πŸš€ Titan V70.0 (Neural Pattern Core + 5-Layer Funnel)")
846
 
847
  with gr.Row():
848
  # LEFT: Chart & Controls