feat(ui): disclose dividend method + honest estimate badge in backtest
Map dividend_method (dated_ledger / dps_annual_proxy / final_holdings_yield _proxy) to an honest Thai label. Show a Proxy badge whenever the dividend is an estimate (everything but dated_ledger) on both the result card and the saved-run history rows, and set the footnote to match the actual method. Frontend build passes.
This commit is contained in:
@@ -149,6 +149,17 @@ function formatNumber(value, digits = 2) {
|
||||
return Number(value ?? 0).toFixed(digits)
|
||||
}
|
||||
|
||||
// map the backend's dividend_method to an honest Thai label/flag
|
||||
function dividendMethodLabel(method) {
|
||||
if (method === 'dated_ledger') return 'ปันผล (ตามวันจริง)'
|
||||
if (method === 'dps_annual_proxy') return 'ประมาณการปันผล/หุ้น (DPS)'
|
||||
return 'ประมาณการปันผล (Proxy)' // final_holdings_yield_proxy or unknown
|
||||
}
|
||||
function dividendIsEstimate(method) {
|
||||
// only dated_ledger rows are real dated cash flows; everything else is an estimate/proxy
|
||||
return method !== 'dated_ledger'
|
||||
}
|
||||
|
||||
function formatDate(value) {
|
||||
if (!value) return '—'
|
||||
return new Date(value).toLocaleString('en-GB', {
|
||||
@@ -695,12 +706,12 @@ onMounted(async () => { await loadDashboard(); await loadBacktestRuns() })
|
||||
<div v-else-if="btResult" class="backtest-results">
|
||||
<div class="bt-kpi-grid">
|
||||
<div class="bt-kpi"><span>กำไรจากราคา</span><strong :class="pnlClass(btResult.price_pnl)">{{ formatNumber(btResult.price_pnl) }} บาท</strong></div>
|
||||
<div class="bt-kpi"><span>ประมาณการปันผล*</span><strong class="positive-text">{{ formatNumber(btResult.dividend_income) }} บาท</strong></div>
|
||||
<div class="bt-kpi"><span>{{ dividendMethodLabel(btResult.dividend_method) }}<span v-if="dividendIsEstimate(btResult.dividend_method)" class="status-tag warning-tag" style="margin-left:6px">Proxy</span></span><strong class="positive-text">{{ formatNumber(btResult.dividend_income) }} บาท</strong></div>
|
||||
<div class="bt-kpi"><span>มูลค่าสุดท้าย</span><strong>{{ formatNumber(btResult.final_value) }} บาท</strong></div>
|
||||
<div class="bt-kpi"><span>ผลตอบแทนสุทธิ</span><strong :class="pnlClass(btResult.net_return)">{{ (btResult.net_return * 100).toFixed(2) }}%</strong></div>
|
||||
</div>
|
||||
<div class="bt-meta muted-cell">Trades: {{ btResult.trades }} · ช่วง {{ btResult.start }} → {{ btResult.end }}</div>
|
||||
<div class="bt-meta muted-cell">*ประมาณจาก dividend yield ของพอร์ตสุดท้าย ไม่ใช่กระแสเงินสดปันผลจริง</div>
|
||||
<div class="bt-meta muted-cell">*{{ dividendIsEstimate(btResult.dividend_method) ? 'ประมาณการปันผล ไม่ใช่กระแสเงินสดปันผลตามวันจริง' : 'ปันผลตามวันจริงจาก ledger (ex-date/per-share)' }}</div>
|
||||
<div v-if="!btResult.leakage_guard" class="bt-meta muted-cell">คำเตือน: ผลนี้ใช้คะแนนปัจจุบันย้อนหลัง จึงเป็น descriptive non-PIT และไม่ใช่หลักฐานประสิทธิภาพกลยุทธ์</div>
|
||||
<div v-if="Object.keys(btResult.holdings || {}).length" class="bt-holdings">
|
||||
<strong>พอร์ตสุดท้าย:</strong>
|
||||
@@ -712,13 +723,13 @@ onMounted(async () => { await loadDashboard(); await loadBacktestRuns() })
|
||||
<div v-if="btRuns.length" class="bt-history">
|
||||
<div class="section-kicker">ประวัติการย้อนทดสอบ</div>
|
||||
<table class="source-table">
|
||||
<thead><tr><th>#</th><th>ช่วง</th><th>ทุน</th><th>กำไรราคา</th><th>ประมาณการปันผล (Proxy)</th><th>ผลตอบแทน</th><th>รันเมื่อ</th></tr></thead>
|
||||
<thead><tr><th>#</th><th>ช่วง</th><th>ทุน</th><th>กำไรราคา</th><th>ปันผล</th><th>ผลตอบแทน</th><th>รันเมื่อ</th></tr></thead>
|
||||
<tbody>
|
||||
<tr v-for="r in btRuns.slice().reverse()" :key="r.id">
|
||||
<td>{{ r.id }}</td><td>{{ r.start }} → {{ r.end }} <span v-if="r.leakage_guard === false" class="status-tag warning-tag" title="ใช้คะแนนปัจจุบันย้อนหลัง ไม่ใช่ point-in-time">descriptive non-PIT</span></td>
|
||||
<td>{{ formatNumber(r.capital) }}</td>
|
||||
<td :class="pnlClass(r.price_pnl)">{{ formatNumber(r.price_pnl) }}</td>
|
||||
<td class="positive-text">{{ formatNumber(r.dividend_income) }}</td>
|
||||
<td class="positive-text">{{ formatNumber(r.dividend_income) }}<span v-if="dividendIsEstimate(r.dividend_method)" class="status-tag warning-tag" title="ประมาณการ ไม่ใช่กระแสเงินสดจริง">Proxy</span></td>
|
||||
<td :class="pnlClass(r.net_return)">{{ (r.net_return * 100).toFixed(2) }}%</td>
|
||||
<td class="muted-cell">{{ r.ran_at ? formatDate(r.ran_at) : '—' }}</td>
|
||||
</tr>
|
||||
|
||||
Reference in New Issue
Block a user