Commit Graph

9 Commits

Author SHA1 Message Date
Kunthawat Greethong
54776d5647 fix(suggestion): profit buckets require combined_score > 0 (owner rule)
Owner: a stock with a NEGATIVE overall (combined) score must not be recommended
in the profit buckets, even with positive momentum + theme. BGRIM/TTB had
combined -0.029/-0.066 yet still landed in bucket 1.

- allocate_capital profit_pool now gates on combined_score > 0 (in addition to
  momentum>0 + theme>0), still ranking by momentum within that pool.
- Verified: bucket 1 now picks PTTGC (+0.209, mom +1.85) instead of BGRIM/TTB;
  BANPU in bucket 2; ADVANC/SCB/LH in bucket 3 by yield. Full suite 377 green.
2026-08-31 19:00:14 +07:00
Kunthawat Greethong
5b8a10c730 refactor(siamchart): momentum is a first-class factor INSIDE the score formula (owner rule)
Owner: momentum must enter the formula (a factor), not be bolted on outside it.
- Single declarative source _SIAMCHART_WEIGHTS = {eps_growth:1.5, dividend_yield:2.0, momentum:0.5}.
- New siamchart_raw_score(g,d,m) = single source of the formula; momentum is an
  explicit term inside it. All 3 call sites (build_siamchart_score + both
  symbol_breakdown spots) now share it — no duplicated arithmetic.
- Pure refactor: outputs unchanged (weights identical). Tests added for the
  momentum-inside-formula rule + momentum raising the score. Full suite 376 green.
2026-08-31 18:50:32 +07:00
Kunthawat Greethong
4c32e2b737 fix(suggestion): load full 50-symbol price snapshot + exclude falling-price names from profit buckets
- load_price_snapshot picked the last snapshot by filename (lexicographic),
  selecting a stale 9-symbol collection over the full 50-symbol universe. Now
  picks the snapshot with the latest source.retrieved_at.
- allocate_capital profit buckets now also require momentum > 0 (a falling-price
  name is not 'ทำกำไร'), while momentum/theme_signal stay Optional so the PIT
  backtest path (which doesn't provide them) still allocates.
- Suggestion now allocates across all 50 SET50 names (B1: BGRIM,TTB; B2: BANPU;
  B3: ADVANC,SCB,LH).
- Regression tests for both. Full suite 374 green.
2026-08-31 10:56:22 +07:00
Kunthawat Greethong
576d9e31ec feat(suggestion): 'ทำกำไร' = price-trend momentum (3/6/12m) gated on positive theme signal
Owner rule: a stock that should be bought for profit is one whose PRICE is
likely to rise in the next 3-6 months — not one with high EPS growth (BTS had
EPS +137% yet flat/falling price). The old selection ranked buckets 1/2 by
 (60/40 theme+siamchart where siamchart was EPS-growth dominated).

- themes.price_trend_score(): blend of ~3/6/12-month price momentum, z-scored
  across the universe (heavier 3/6m weight per the 3-6 month tenure).
- allocate_capital: buckets 1/2 rank by momentum, gated on theme_signal > 0
  (mean surprise across the symbol's themes). theme_signal=None (backtest path)
  is not gated so PIT backtest still allocates. Bucket 3 unchanged (yield top).
- suggestion endpoint passes real momentum + theme_signal from the live board.
- Verified: bucket 1 now picks CRC/BEM (dividend + rising price); falling-price
  PTT/MINT go to bucket 3 by yield, not bucket 1. Full suite 372 green (3 new
  momentum/theme-gate tests).
2026-08-31 10:05:00 +07:00
Kunthawat Greethong
be6a92540c feat(backtest): runnable with partial factor coverage + oldest-history default (owner rule)
Owner's rule: backtest must run as soon as there's enough data to estimate an
investment — it must NOT be blocked just because some sources lack deep PIT
history. Scoring is deliberately flexible (a theme uses whatever subset of
factors was knowable that day).

- backtest_readiness: readiness = usable window (price + Siamchart + >=1 factor),
  not all-factors-present. Missing factors still reported (transparency) but no
  longer block the run. recommended_start = oldest executable price (oldest
  history the system holds); recommended_end = last complete trading day.
- pit_scorer.theme_surprise_report: flexible — skips factors not released by
  as_of; blocked only when NO factor has a value. pit_meta.partial_pit reflects
  themes scored from a partial factor subset.
- Verified end-to-end: readiness ready=true (recommended 2024-01-03 -> 2026-08-29);
  POST /api/v1/backtest/run default window returns 201 full result (1M -> final
  equity 1,117,243.95), no 400 from missing factors.
- test_backtest_readiness updated to earliest-runnable semantics; full suite 369 green.
2026-08-30 20:27:22 +07:00
Kunthawat Greethong
7f175e5a05 feat(scoring): flexible source fallback (no board crash) + per-source calc audit (Q2, Q3)
Q2 flexible scoring: _fetch_with_cache now degrades instead of raising
DashboardError — a source that fails with no cached value returns {} so the
theme scorer drops that source's factors; a previously-good value is kept as
stale by the daily cache. Verified: all-sources-down still builds 13 themes.

Q3 per-source audit: new themes.factor_source_breakdown(fetched, theme) shows
per factor source/raw/normalized/weight/contribution; dashboard exposes
fetch_data + factor_sources; per-symbol modal renders symbolDetail.factor_sources
(e.g. retail: te_thailand ยอดขายปลีก -14.5 -> -1.0 x 0.7 = -0.7).

Suite 369 green; independent review passed: true.
Q1 (HAR for deferred sources) spike recorded: method works, REIC needs deeper
interaction; NBTC 403 likely unbpassable without a session.
2026-08-29 12:15:54 +07:00
Kunthawat Greethong
51400f20c7 docs: record IRPC review verdict (passed) + open no-fixture-fallback tradeoff 2026-08-29 11:14:02 +07:00
Kunthawat Greethong
12b34929d7 feat(factor): add energy_irpc (IRPC net margin) as 2nd Thai refiner signal
- new energy_irpc collector parsing IRPC performance-highlights table
  (net profit/EBITDA/ROE margins, latest period 3M26: +10.27%)
- factor energy_irpc_net_margin (sign +1) wired into refining_energy/
  exploration/utilities, extending the energy theme beyond TOP
- scheduler job + dashboard fetch + sources table row (now 9 sources)
- tests: parse (incl paren-negatives), value-key resolution, direction;
  suite 368 OK. Independent review passed: true
- Phase B feasibility: REIC/EPPO/NBTC/PTTEP are JS-rendered or anti-bot
  (recorded deferred in plan); IRPC was the clean server-rendered win
2026-08-29 11:13:17 +07:00
Kunthawat Greethong
dbb787c50a docs: data-source expansion plan + engineering log (te_thailand, sign fix, ui fix) 2026-08-29 09:19:06 +07:00