diff --git a/frontend/src/App.vue b/frontend/src/App.vue index b602c5e..f83b3c1 100644 --- a/frontend/src/App.vue +++ b/frontend/src/App.vue @@ -259,11 +259,21 @@ async function runSimulation() { simLoading.value = true simResult.value = null try { - simResult.value = await fetchJson('/api/v1/simulation', { - method: 'POST', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ capital: Number(simCapital.value), mode: simMode.value }), - }) + if (simMode.value === 'forward') { + // REAL forward lifecycle (not cosmetic): freeze + execute a paper run. + simResult.value = await fetchJson('/api/v1/forward', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ capital: Number(simCapital.value), use_pit: false }), + }) + await loadForward() + } else { + simResult.value = await fetchJson('/api/v1/simulation', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ capital: Number(simCapital.value), mode: 'backtest' }), + }) + } } catch (caught) { notice.value = caught.message } finally { @@ -271,6 +281,38 @@ async function runSimulation() { } } +// ---- real forward-test lifecycle (durable paper runs) ---- +const fwdRuns = ref([]) +const fwdLoading = ref(false) + +async function loadForward() { + fwdLoading.value = true + try { + const body = await fetchJson('/api/v1/forward') + fwdRuns.value = body.runs ?? [] + } catch (caught) { + notice.value = caught.message + } finally { + fwdLoading.value = false + } +} +async function markForward(id) { + try { + await fetchJson(`/api/v1/forward/${id}/mark`, { method: 'POST' }) + await loadForward() + } catch (caught) { + notice.value = caught.message + } +} +async function matureForward(id) { + try { + await fetchJson(`/api/v1/forward/${id}/mature`, { method: 'POST' }) + await loadForward() + } catch (caught) { + notice.value = caught.message + } +} + async function loadDashboard() { loading.value = true error.value = '' @@ -300,6 +342,7 @@ async function loadDashboard() { paperAuthWarning.value = sessionBody.warning || '' backtest.value = backtestBody researchRun.value = researchBody + await loadForward() // load durable forward-test runs (not cosmetic) } catch (caught) { error.value = caught.message } finally { @@ -679,6 +722,34 @@ onMounted(async () => { await loadDashboard(); await loadBacktestRuns() })
สร้าง forward run → สัญญาณ (คะแนน) ถูก freeze ทันทีที่สร้าง แล้ว execute ด้วยราคาหลัง freeze. กด Mark ตามราคาล่าสุด, Mature เพื่อปิด run. เป็น Paper เท่านั้น.
+| # | สถานะ | ทุน | ลงทุน | ถือ | ผลตอบแทน | ตรวจ |
|---|---|---|---|---|---|---|
| {{ run.id.slice(0, 12) }} | ++ {{ run.status }} + non-PIT + | +{{ formatNumber(run.capital, 0) }} | +{{ formatNumber(run.invested, 0) }} | +{{ Object.keys(run.holdings || {}).join(', ') || '—' }} | +{{ run.net_return != null ? (run.net_return * 100).toFixed(2) + '%' : '—' }} | ++ + + ปิดแล้ว + | +