File size: 3,409 Bytes
558db1e
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
def build_data_alerts_html(tn_ratio, n_fragile):
    data_alerts_html = ""
    if tn_ratio is not None and tn_ratio < 10:
        sev_c = "#f85149" if tn_ratio < 5 else "#d29922"
        sev_l = "Critical" if tn_ratio < 5 else "Warning"
        data_alerts_html += (
            f'<div style="background:#161b22;border:1px solid {sev_c};border-radius:8px;'
            f'padding:10px 14px;margin-bottom:12px;font-size:.8rem;color:{sev_c}">'
            f'<strong>&#9888; Spurious Correlation {sev_l}</strong> — '
            f'T/N={tn_ratio:.1f}x. Need ≥10× observations vs assets.</div>'
        )
    if n_fragile > 0:
        data_alerts_html += (
            f'<div style="background:#161b22;border:1px solid #d29922;border-radius:8px;'
            f'padding:10px 14px;margin-bottom:12px;font-size:.8rem;color:#e3b341">'
            f'<strong>&#9888; Fragile Allocations</strong> — {n_fragile} asset(s) had '
            f'weight swings >15 pp under ±10% return noise. Stability penalty applied.</div>'
        )
    return data_alerts_html

def build_warnings_html(diags):
    warn_html = ""
    if diags:
        items = "".join(f'<li style="color:#f85149">{d}</li>' for d in diags)
        warn_html = (
            '<div style="background:#2d1114;border:1px solid #f85149;border-radius:8px;'
            'padding:14px;margin-bottom:16px">'
            '<p style="color:#f85149;font-weight:700;margin-bottom:8px">&#9888; Behavioral Diagnostics</p>'
            f'<ul style="padding-left:18px">{items}</ul></div>'
        )
    return warn_html

def build_constraint_diag_html(model_info):
    relax_log = model_info.get("relaxation_log", [])
    binding_cons = model_info.get("display_constraints", [])
    
    _cd_inner = ""
    if binding_cons:
        _bc_items = "".join(f'<li style="color:#e3b341;margin-bottom:4px">{c}</li>' for c in binding_cons)
        _cd_inner += (
            '<p style="color:#e3b341;font-weight:700;margin:0 0 5px">Binding Constraints</p>'
            '<p style="color:#8b949e;font-size:.8rem;margin:0 0 8px">'
            'These rules actively limited the optimizer &mdash; relaxing them may improve returns:</p>'
            f'<ul style="padding-left:18px;margin:0 0 12px">{_bc_items}</ul>'
        )
    
    if relax_log:
        _rl_items = "".join(f'<li style="color:#f0883e;margin-bottom:4px">{r}</li>' for r in relax_log)
        _cd_inner += (
            '<p style="color:#f0883e;font-weight:700;margin:0 0 5px">Constraint Relaxation History</p>'
            '<p style="color:#8b949e;font-size:.8rem;margin:0 0 8px">'
            'Initial constraints were infeasible &mdash; the engine auto-relaxed these rules to find a solution:</p>'
            f'<ul style="padding-left:18px;margin:0">{_rl_items}</ul>'
        )
    elif not binding_cons:
        _cd_inner = (
            '<p style="color:#3fb950;font-weight:700;margin:0 0 4px">All Constraints Satisfied</p>'
            '<p style="color:#8b949e;font-size:.8rem;margin:0">'
            'No binding constraints or relaxations required. The optimizer found a clean solution.</p>'
        )
        
    return (
        '<div style="background:#161b22;border:1px solid #30363d;border-radius:8px;'
        'padding:16px;margin-bottom:16px">'
        '<p style="color:#58a6ff;font-weight:700;margin:0 0 12px;font-size:.9rem">'
        'Constraint Diagnostics</p>'
        f'{_cd_inner}</div>'
    )