fix(ui): show theme weighted-average verification in per-source modal

After reviewer suggestion: per theme, display sum(contribution)/sum(|weight|) =
theme surprise so the owner can confirm the source audit matches the real score.
This commit is contained in:
Kunthawat Greethong
2026-08-29 12:18:40 +07:00
parent 7f175e5a05
commit 3010ab287f
4 changed files with 41 additions and 20 deletions

File diff suppressed because one or more lines are too long

18
frontend/dist/assets/index-DDvZwbpd.js vendored Normal file

File diff suppressed because one or more lines are too long

View File

@@ -5,7 +5,7 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="theme-color" content="#0b1018" />
<title>SET50 Signal Lab</title>
<script type="module" crossorigin src="/assets/index-C6jTIiYC.js"></script>
<script type="module" crossorigin src="/assets/index-DDvZwbpd.js"></script>
<link rel="stylesheet" crossorigin href="/assets/index-CUx7tUuk.css">
</head>
<body>

View File

@@ -154,6 +154,22 @@ function formatNumber(value, digits = 2) {
return Number(value ?? 0).toFixed(digits)
}
// Per-theme factor audit helpers: verify sum(contribution)/sum(|weight|) = surprise
function themeContribSum(rows) {
return (rows || []).reduce((s, r) => s + (r.contribution ?? 0), 0)
}
function themeWeightSum(rows) {
return (rows || []).reduce((s, r) => s + Math.abs(r.weight ?? 0), 0)
}
function themeWeightedAvg(rows) {
// only contributing (non-missing) factors count, matching compute_theme_surprises
const used = (rows || []).filter((r) => !r.missing && r.normalized != null)
const cs = themeContribSum(used)
const ws = themeWeightSum(used)
if (ws === 0) return null
return Math.max(-1, Math.min(1, cs / ws))
}
// map the backend's dividend_method to an honest Thai label/flag
function dividendMethodLabel(method) {
if (method === 'dated_ledger') return 'ปันผล (ตามวันจริง)'
@@ -910,8 +926,13 @@ onMounted(async () => { await loadDashboard(); await Promise.all([loadBacktestRu
</tr>
</tbody>
</table>
<!-- weighted-average verification: sum(contrib) / sum(|weight|) = theme surprise -->
<div class="calc-z" style="margin-top:4px">
<span v-if="themeWeightedAvg(rows) != null">Σcontrib {{ formatNumber(themeContribSum(rows), 4) }} ÷ Σ{{ '|w|' }} {{ formatNumber(themeWeightSum(rows), 2) }} = ธีม surprise <strong>{{ formatNumber(themeWeightedAvg(rows), 3) }}σ</strong></span>
<span v-else class="muted-cell">งไมอม factor</span>
</div>
</div>
<div class="modal-sub">normalized = raw ปรบดวย sign/center/span อยในชวง [-1,1]; contribution = weight × normalized. แหลงทไมอมลจะไมกน (missed drop source)</div>
<div class="modal-sub">normalized = raw ปรบดวย sign/center/span อยในชวง [-1,1]; contribution = weight × normalized; theme surprise = Σcontribution ÷ Σ{{ '|weight|' }}. แหลงทไมอมลจะไมกน (drop source)</div>
</div>
<div v-else class="muted-cell">ไมอมลแยกตามแหล</div>
</div>