""" ui/mc_components.py Streamlit UI components for MC Dropout uncertainty display. Designed to slot into the existing app.py display flow alongside the existing show_conviction_panel() and show_signal_banner() calls. All functions are self-contained — no changes to existing ui/components.py needed. Usage in app.py --------------- Replace the existing predict + conviction block in run_module(): # OLD preds, proba = predict_approach1(model, X_test_s) conviction = compute_conviction(proba[-1], target_etfs) # NEW (drop-in) from models.mc_dropout import mc_predict_approach1 from signals.mc_conviction import compute_mc_conviction from ui.mc_components import show_mc_conviction_panel, show_mc_uncertainty_bar preds, mean_proba, uncertainty = mc_predict_approach1(model, X_test_s, n_passes=50) mc_conv = compute_mc_conviction(mean_proba[-1], uncertainty[-1], target_etfs) show_mc_conviction_panel(mc_conv) show_mc_uncertainty_bar(mc_conv) """ from __future__ import annotations import numpy as np import streamlit as st from signals.mc_conviction import uncertainty_summary_text # ── MC Conviction Panel ──────────────────────────────────────────────────────── def show_mc_conviction_panel(mc_conv: dict, n_passes: int = 50) -> None: """ Full MC Dropout conviction panel. Replaces show_conviction_panel() when MC Dropout is enabled. Displays: - Best ETF + Z-score conviction label (same as existing panel) - CASH override banner if cash_flag is True - Uncertainty label + mean σ - Adjusted conviction score - Per-ETF probability bars (mean_proba) - Per-ETF uncertainty bars (std across passes) """ best_name = mc_conv["best_name"] z = mc_conv["z_score"] adj_z = mc_conv["adjusted_z"] label = mc_conv["label"] unc_label = mc_conv["unc_label"] unc_color = mc_conv["unc_color"] cash_flag = mc_conv["cash_flag"] mean_unc = mc_conv["mean_uncertainty"] unc_score = mc_conv["unc_score"] from signals.conviction import conviction_color, conviction_icon conv_color = conviction_color(label) icon = conviction_icon(label) st.markdown("### 🎯 MC Dropout Signal Conviction") st.caption(f"Based on {n_passes} stochastic forward passes · Dropout active at inference") # ── CASH override ────────────────────────────────────────────────────────── if cash_flag: st.error( f"⚠️ **CASH OVERRIDE** — Uncertainty too high to commit. \n" f"{mc_conv['cash_reason']}" ) # ── Top metrics row ──────────────────────────────────────────────────────── col1, col2, col3, col4 = st.columns(4) with col1: st.metric( label="Best ETF", value=f"{icon} {best_name}", delta=None, ) with col2: st.metric( label="Conviction (Z)", value=f"{z:.2f}", delta=label, ) with col3: st.metric( label="Adjusted Conviction", value=f"{adj_z:.2f}", help="Z-score × uncertainty score. Lower when model is uncertain.", ) with col4: st.metric( label="Uncertainty", value=f"{mean_unc:.3f} σ̄", delta=unc_label, delta_color="inverse", ) st.divider() # ── Side-by-side bars: probability vs uncertainty ───────────────────────── col_prob, col_unc = st.columns(2) with col_prob: st.markdown("**Mean Probability (across passes)**") sorted_pairs = mc_conv["sorted_pairs"] for name, score in sorted_pairs: pct = float(score) * 100 bar = "█" * int(pct / 5) color = conv_color if name == best_name else "#888888" st.markdown( f"