Files
Apex_AI_MT5_EA_Optimizer/ui/templates/reports_index.html
T
LEGSTECH Optimizer b70a6760ae fix: 6 workflow flaws detected via full system test
1. CRITICAL FIX - Reports 500 Internal Server Error:
   Root cause: {{}} in onclick was Jinja2 template expression
   Fix: Changed to single {} in reports_index.html onclick

2. Score history chart always empty:
   Root cause: score_update only emitted inside wfv.passed block
   Fix: Emit score_update after every hypothesis run with {promoted:false}
   Fix: Baseline run also pushes to chart via run_complete handler

3. IS gate too strict - optimizer produces 0 candidates forever:
   Root cause: min_calmar=0.35 but best EA has calmar=0.165
   Fix: Two-tier IS check - passes if composite_score improves vs baseline
   (absolute thresholds still apply as alternative pass condition)

4. Findings emitted twice (double UI display):
   Root cause: baseline analyzed once after run, then re-analyzed in iter 1
   Fix: Cache baseline findings, reuse in iteration 1 without re-emitting

5. Chart labels improved:
   'Baseline' for first point, 'It1·h1' for hypothesis runs
   Calmar normalized -0.5..2.0 -> 0..1 for chart display

6. Best score header only updates on actual promotion (not per-hypothesis)
2026-04-13 03:45:14 +00:00

94 lines
4.4 KiB
HTML

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Reports — MT5 Optimizer</title>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;600;700;800&family=JetBrains+Mono:wght@400;500&display=swap" rel="stylesheet">
<style>
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
body { background: #0a0d14; color: #e2e8f8; font-family: 'Inter', sans-serif; font-size: 13px; padding: 32px; }
header { display: flex; align-items: center; justify-content: space-between; margin-bottom: 32px; }
h1 { font-size: 22px; font-weight: 800; }
.sub { color: #6b7fa3; font-size: 12px; margin-top: 4px; }
.back-link { color: #4f8ef7; text-decoration: none; font-size: 12px; }
.back-link:hover { text-decoration: underline; }
.empty { color: #3d4f70; text-align: center; padding: 80px 0; font-size: 16px; }
.cards { display: grid; grid-template-columns: repeat(auto-fill, minmax(320px, 1fr)); gap: 16px; }
.run-card {
background: #111621; border: 1px solid #1e2740; border-radius: 12px; padding: 18px 20px;
transition: border-color 0.2s, transform 0.2s;
text-decoration: none; color: inherit; display: block;
}
.run-card:hover { border-color: #4f8ef7; transform: translateY(-2px); }
.run-header { display: flex; justify-content: space-between; align-items: flex-start; margin-bottom: 12px; }
.run-id { font-family: 'JetBrains Mono', monospace; font-size: 11px; color: #6b7fa3; }
.run-score { font-size: 28px; font-weight: 800; font-family: 'JetBrains Mono', monospace; color: #22d3a5; }
.run-phase { font-size: 10px; padding: 2px 8px; border-radius: 4px; background: rgba(79,142,247,0.15); color: #4f8ef7; font-weight: 700; text-transform: uppercase; }
.metrics-row { display: grid; grid-template-columns: repeat(3, 1fr); gap: 8px; margin-top: 10px; }
.m { text-align: center; background: #161c2a; border-radius: 6px; padding: 6px 8px; }
.m-label { font-size: 9px; color: #6b7fa3; text-transform: uppercase; letter-spacing: 0.5px; }
.m-val { font-size: 14px; font-weight: 700; font-family: 'JetBrains Mono', monospace; margin-top: 2px; }
.delta-up { color: #22d3a5; } .delta-dn { color: #f44; }
.run-ts { font-size: 10px; color: #3d4f70; margin-top: 10px; font-family: 'JetBrains Mono', monospace; }
</style>
</head>
<body>
<header>
<div>
<h1>📁 Optimization Reports</h1>
<div class="sub">{{ runs|length }} run(s) recorded · Click any card to open the full report</div>
</div>
<a class="back-link" href="/" onclick="if(document.referrer){history.back();return false;}">&#8592; Back to Dashboard</a>
</header>
{% if not runs %}
<div class="empty">No reports yet.<br>Start the optimizer to generate your first run report.</div>
{% else %}
<div class="cards">
{% for r in runs %}
<a class="run-card" href="/reports/{{ r.run_id }}/summary.html" target="_blank">
<div class="run-header">
<div>
<div class="run-id">{{ r.run_id }}</div>
<div class="run-score">{{ "%.4f"|format(r.score) }}</div>
</div>
<span class="run-phase">{{ r.phase }}</span>
</div>
<div class="metrics-row">
<div class="m">
<div class="m-label">Net Profit</div>
<div class="m-val {% if r.net_profit >= 0 %}delta-up{% else %}delta-dn{% endif %}">
${{ "%.0f"|format(r.net_profit) }}
</div>
</div>
<div class="m">
<div class="m-label">Calmar</div>
<div class="m-val">{{ "%.2f"|format(r.calmar) }}</div>
</div>
<div class="m">
<div class="m-label">Drawdown</div>
<div class="m-val delta-dn">{{ "%.1f"|format(r.drawdown_pct) }}%</div>
</div>
<div class="m">
<div class="m-label">PF</div>
<div class="m-val">{{ "%.2f"|format(r.profit_factor) }}</div>
</div>
<div class="m">
<div class="m-label">Trades</div>
<div class="m-val">{{ r.total_trades }}</div>
</div>
<div class="m">
<div class="m-label">Score Δ</div>
<div class="m-val {% if r.score_delta >= 0 %}delta-up{% else %}delta-dn{% endif %}">
{{ "%+.4f"|format(r.score_delta) }}
</div>
</div>
</div>
<div class="run-ts">{{ r.ts[:19].replace("T"," ") }} UTC</div>
</a>
{% endfor %}
</div>
{% endif %}
</body>
</html>