Files
set50-system/.hermes/plans/2026-08-25_092044-multi-theme-dashboard-and-simulation-r2.md

8.9 KiB
Raw Permalink Blame History

Multi-Theme + Simulation Implementation Plan — REVISION 2

For Hermes: Execute task-by-task with todo tracking and per-task commits. TDD for all logic; visual verification for UI/CSS.

Goal: Rebuild the single-theme tourism demo into a multi-theme research platform with (a) a combined dashboard (all themes + stock recommendation table), (b) per-theme detail pages, (c) a capital allocation simulation (same engine used for both backtest and forward test), and (d) an MT5 order interface (forward test sends dry-run orders; live gate kept off in this round). UI in Thai (technical terms stay English). Uses real data + daily cache, not mocks.

Themes (3 alternative factors):

  1. tourism — Tourism Pulse (signal exists, real BOT data path)
  2. auto_credit — Auto Credit Cycle (registry slot; data pipeline needs a real source before it can score)
  3. refining_energy — Refining / Energy Spread (registry slot; data pipeline TBD)

Siamchart is treated as a fundamental data provider, not a theme. It supplies PE/EPS/Yield/P/BV/ROE per symbol and contributes to the combined score with a lower weight.


Confirmed requirements (from user, 2026-08-25)

  1. 3 themes = 3 alternative factors (tourism, auto_credit, refining_energy). A symbol can appear in multiple themes.
  2. Score combining: each symbol has a theme score (average across all themes that score it) and a siamchart score. Combined = theme_score × 60% + siamchart_score × 40%.
  3. 8-symbol live data is OK for testing logic; production must cover the full universe (collectors must be scalable, not hard-coded to 8).
  4. "ไม่จ่ายปันผล" (bucket 2) = a high-score stock that does not pay a dividend (is_dividend = False / yield ≤ 0).
  5. Paper ledger is replaced by a forward test that reuses the same simulation engine as backtest — the only difference is real MT5 order dispatch. We build the MT5 order interface; live dispatch remains gated off (forward/dry-run in this round).
  6. Data quality / provenance = real sources, cached daily — not fixture mocks. Provenance shows where each alternative factor comes from.
  7. Signal board + Stock board = ONE table, signal-focused.
  8. UI language = Thai (technical terms English).
  9. Remove unused/unnecessary dashboard sections.

PART A — Multi-Theme Backend

Task A1: Theme registry

Files: create backend/app/themes.py; create backend/tests/test_themes.py

Registry with 3 theme slots + their factor provider. list_themes() returns them. Registry is pluggable so a theme can be enabled=False while its data pipeline is absent.

Task A2: Combined signal aggregation

Files: modify backend/app/themes.py, backend/app/__init__.py; tests

/api/v1/dashboard returns:

  • Per-symbol theme_score = mean of enabled themes that score it
  • siamchart_score (normalized)
  • combined_score = 0.6 * theme_score + 0.4 * siamchart_score
  • side (LONG/SHORT/NEUTRAL) from combined
  • per-theme contributions

Normalization: each provider's raw score is z-scored (or min-max over the live universe) before combining, so weights are meaningful across heterogeneous scales.

Task A3: Per-theme detail endpoint

/api/v1/themes/<id> — 404 unknown; returns that theme's observations/surprise/signals/lineage. Also exposes /api/v1/themes (registry incl. enabled status + data source).

Task A4: Daily cache layer (real data, no mocks)

Files: create backend/app/daily_cache.py; tests

Fetch-once-then-cache daily:

  • Keyed by (source, as_of).
  • TTL ~24h; stale-if-error fallback to last good cache.
  • Ensures tourism + siamchart reads hit cache instead of re-fetching every dashboard load, and sets up the "update daily" cadence the user wants.

PART B — Simulation / Backtest / Forward-Test Engine

Task B1: Price-series loader

Files: create backend/app/simulation.py; tests

Load Yahoo price snapshot series[SYM].bars{date: adjusted_close} for all symbols. Covers 2024-01-03 → 2026-08-24.

Task B2: Capital allocation core (allocate_capital)

Files: backend/app/simulation.py + tests

Given capital, per-symbol combined_score, is_dividend, dividend_yield, latest price:

  • Bucket 1 (50%) — highest combined_score among dividend-paying names.
  • Bucket 2 (20%) — highest combined_score among non-dividend names.
  • Bucket 3 (30%) — highest dividend yield among names not already bought in bucket 1 (ignores score).

Per symbol: minimum 100 shares. Rank by combined_score desc. If a bucket's first pick can't afford 100 shares, try progressively cheaper eligible names (that still pass the bucket's criteria). If no eligible name fits, leave remainder as cash.

  • Allocation math: qty = max(100, floor(available_cash / price / 100) * 100) within bucket cash.
  • Overflow flows bucket → bucket → cash.

Task B3: Simulation endpoint + forward-test mode

Files: backend/app/__init__.py; tests

  • POST /api/v1/simulation {capital} → allocation plan (per-bucket orders, qty, notional, total, unallocated cash, data caveat: revised history not PIT).
  • POST /api/v1/simulation/forward — same engine, but marks orders execution=paper and, if an MT5 bridge is configured, would dispatch. Live dispatch gated off (env MT5_ENABLE_ORDER must be set AND explicit approval).

Task B4: MT5 order interface (interface only, live gated)

Files: create backend/app/mt5_bridge.py; tests (mock MetaTrader5 per mt5-data-service skill gotcha)

Abstract MT5Bridge with: connect, symbol_resolve, order_new (dry-run default), and a structural kill switch — no real dispatch path in code unless MT5_ENABLE_ORDER=1 AND explicit user approval. Follows the mt5-data-service / mql5-ea-development skill patterns (Windows-only MetaTrader5 stub for tests).


PART C — Frontend Multi-Theme UI (Thai, signal-first)

Task C1: Route shell

Files: frontend/src/App.vue, style.css

Hash-routing: #/ (dashboard), #/theme/:id, #/simulation. Sidebar nav in Thai: แดชบอร์ด, ธีม, การจำลอง (Simulation).

Task C2: Combined Dashboard (Thai)

  • Theme strip: each active theme's surprise/label.
  • ONE stock table (signal-first: combined score, side, theme contributions, then fundamentals PE/EPS/Yield/P/BV/ROE). Dividend filter + sortable columns kept. This replaces the separate Signal board + Stock board.
  • Remove unused sections (Paper Ledger card, live receiver text, etc.).

Task C3: Theme detail page

#/theme/:id — that theme's observations (surprise bars), provenance (source used), and its signal contribution table.

Task C4: Simulation tab

#/simulation — Thai UI: enter capital, choose backtest/forward, render 3 buckets with orders; show unallocated cash and the "revised history, paper-only" caveat.

Task C5: Provenance (real data)

Dashboard provenance section reads from live cache metadata: source id, retrieved_at (daily cache), raw hash. No fixture labels.


Data requirements / open items (NOT guessed)

  • auto_credit data source: needs a real public/paid source for vehicle sales, auto loan growth, auto NPL. Not yet identified. auto_credit theme stays in registry as enabled=False until a source + collector exist.
  • refining_energy data source: crack/GRM spread or Thai refining/energy stats. Not yet identified. enabled=False until built.
  • Full SET50 universe prices: Yahoo history currently covers 8 symbols; production simulation needs price history for the full universe. Requires extending the price collector to all symbols (scrape/SETSMART/MT5).

The three-theme registry is the interface; this round builds tourism + siamchart fully (real, cached) and stubs auto/energy until their data exists. Simulation works on whatever real symbols have both a price series and a score.


Verification

  1. Full backend suite (-W error unittest discover) all pass (existing 140 + new).
  2. cd frontend && npm run build success.
  3. Browser (Thai): dashboard lists themes (enabled + disabled), combined signal-first table with dividend filter + sort, simulation returns allocation, per-theme detail works.
  4. git diff --check, static scan clean, independent fail-closed code review.
  5. Per-task commits.

Closed/open per user's 10 points

# User requirement Status in plan
1 3 themes (tourism, auto, energy) Registry + tourism live; auto/energy enabled=False pending data source
2 combined = 60% theme + 40% siamchart A2
3 8-symbol OK for logic, prod full Simulation scales to any symbol with price+score
4 bucket2 = high score, no dividend B2
5 paper→forward test = same engine; MT5 iface B3, B4
6 real data + daily cache, provenance real A4, C5
7 one signal-first table C2
8 Thai UI C1C4
9 remove unused C2
10 (mt5 scope) interface built, live gated B4