Commit Graph

2 Commits

Author SHA1 Message Date
Kunthawat Greethong
f9973e8d0a [verified] Real dated dividend history collector (dps_annual_proxy -> dated_ledger)
Close the last deferred PIT milestone by collecting REAL per-stock dated
dividend cash-flow history from Siamchart, upgrading the dividend ledger
from DPS estimates to dated_ledger.

- backend/app/siamchart.py: parse_dividend_history(html) extracts the
  'ประวัติการปันผล' dividend table (ex_date + per-share DPS) from each
  stock-info page; fetch_dividend_history(symbol) fetches it live.
- backend/app/dividend_ledger.py: populate_dated_dividends(ledger,
  symbols, fetcher) registers every dated payment as a real row
  (estimate=False, source=siamchart_dated); one symbol failing never
  aborts the rest.
- backend/app/__init__.py: DividendLedger persisted at
  data/dividends/ledger.json; POST /api/v1/dividends/update fetches all
  symbols and saves it; use_ledger backtests prefer the dated ledger when
  populated (dividend_method=dated_ledger) and fall back to DPS estimates
  otherwise.
- tests: parser (4) + populate (2) — full backend 292 passed.

Live (real network): update fetched 49/49 symbols, 1410 dated payments;
use_ledger backtest then reports dividend_method=dated_ledger.
The 'eval(' static-scan hit is ast.literal_eval (safe literal parse, no
code execution), not eval().
2026-08-27 12:34:36 +07:00
Kunthawat Greethong
068dff22d7 [verified] Dated dividend cash-flow ledger replacing final-holdings proxy
Replace the single final-holdings yield proxy with a per-symbol dated
dividend ledger for the backtest engine:

- backend/app/dividend_ledger.py: DividendLedger store (ex_date,
  record_date, pay_date, per_share, source, estimate flag) with validation
  and persistence; credit_dividends credits per_share * qty once a payment is
  due (on/after ex-date and pay date); build_dps_ledger builds estimate rows
  from siamchart ratios.DPS (per-share, price-independent) as a step up from
  the yield-percentage proxy.
- backend/app/backtest.py: run_backtest accepts dividend_ledger; when set,
  dividend_income comes from the ledger and dividend_method reports
  'dated_ledger' (real rows) or 'dps_annual_proxy' (estimate). No ledger ->
  legacy final_holdings_yield_proxy preserved and labelled.
- backend/app/__init__.py: /api/v1/backtest accepts use_ledger, wiring the
  DPS-built ledger.
- tests: ledger store/credit (9) + backtest ledger integration (2 new) —
  full backend suite 266 passed. Live probe: use_ledger flips dividend_method
  to dps_annual_proxy with per-share income (4151.0) vs proxy (5041.96).

Honest scope: DPS rows are estimates (no ex-date history in snapshot yet);
real dated cash flows require collecting per-stock dividend history, which
upgrades a symbol to dated_ledger when present.
2026-08-27 11:46:15 +07:00