Commit Graph

874 Commits

Author SHA1 Message Date
Sam Smith
a3c039ac13 feat: add feishu file upload support for report delivery (#1932)
* feat: add feishu file upload support for report delivery

- Add FEISHU_SEND_AS_FILE config option to switch from text to file delivery
- Implement FeishuSender.send_feishu_file() with App Bot SDK upload + webhook fallback
- Integrate file upload path into pipeline dashboard notification loop
- Integrate file upload path into NotificationService.send_report()
- Add save_and_send_feishu_file() convenience wrapper
- Add .env.example entry and CHANGELOG.md record

* fix: restrict feishu file mode to report routes and wire into workflow

- Limit FEISHU_SEND_AS_FILE to route_type=None or 'report' in
  _send_to_static_channel, preventing alert/event paths from
  unexpectedly saving alerts as files (Codex review P2).
- Add FEISHU_SEND_AS_FILE env var to .github/workflows/00-daily-analysis.yml
  so the setting is available in scheduled runs (Codex review P2).
- Add 13 tests: 7 FeishuSender unit tests (send_feishu_file webhook/App Bot
  paths), 6 NotificationService integration tests (route_type filtering)

* fix: address round-2 review blockers

Correctness:
- Remove route_type=None file-mode fallback; only explicit
  route_type='report' triggers Feishu file delivery
  (api/v1/endpoints/agent.py calls send() without route_type)

Compatibility:
- Isolate CreateFileRequest/CreateFileRequestBody imports from
  CreateMessageRequest; add FEISHU_FILE_SDK_AVAILABLE flag
  so old lark-oapi without file-upload classes won't break
  existing App Bot text messaging

Test fix:
- Fix webhook test assertion: # Test Report -> **Test Report**
  (format_feishu_markdown converts markdown headings to bold)

Documentation:
- Add FEISHU_SEND_AS_FILE to docs/notifications.md config table
- Add file-send section to docs/bot/feishu-bot-config.md
  (permissions, deps, webhook fallback, route scope, CI mapping)
- Add FEISHU_SEND_AS_FILE to docs/full-guide.md and
  docs/full-guide_EN.md config tables
- Add Feishu file create OpenAPI link to docs/notifications.md

* docs: fix feishu_sender drift and document config entry boundary

- Fix outdated '本轮未改动 feishu_sender.py' line in docs/notifications.md
  (we added send_feishu_file to feishu_sender.py)
- Document FEISHU_SEND_AS_FILE as .env/Actions-only in
  docs/bot/feishu-bot-config.md (not exposed in Web/Desktop settings)

* feat: add FEISHU_SEND_AS_FILE to system_config_service env mapping

- Add FEISHU_SEND_AS_FILE -> feishu_send_as_file (bool) mapping
  alongside FEISHU_MAX_BYTES in the notification env key mapping
- Update docs/bot/feishu-bot-config.md to reflect standard config paths

* test: add non-mock SDK import smoke test for file upload classes
2026-07-06 21:26:19 +08:00
zhulinsen
267c2139ae docs: clarify data source configuration (#1935) 2026-07-05 20:57:42 +08:00
Alfred
36f03c06e2 feat: add decision signal stock context (#1925)
Co-authored-by: zhulinsen <42829555+ZhuLinsen@users.noreply.github.com>
2026-07-05 19:22:23 +08:00
zhulinsen
01addc6318 refactor: simplify settings page layout (#1923)
* refactor: simplify settings page layout

* refactor: refine settings responsive layout

* fix(review-feedback-1923): docs/CHANGELOG.md 未更新
2026-07-05 19:20:13 +08:00
zhulinsen
523c7b00de fix: keep WebUI bind options consistent (#1922)
* fix: keep WebUI CLI bind options authoritative

* fix(review-feedback-1922): apps/dsa-web/src/locales/settingsHelp.ts 未随本次 CLI/WebUI 绑定语义更新
2026-07-05 19:19:10 +08:00
Gach-Coder
a43daa4331 Merge pull request #1889 from Gach-Coder/docs/add-data-source-guide
docs: 在 README 快速开始中添加行情数据源配置说明 (get259#1775)
2026-07-05 19:17:13 +08:00
Shlok Goyal
34f02af617 Ci/dingtalk GitHub actions (#1918)
* ci: map DingTalk secrets to daily analysis workflow

* docs: sync github actions documentation table for DingTalk

* docs: add changelog entry for DingTalk GitHub Actions mapping
2026-07-04 21:46:28 +08:00
zhulinsen
c1a324d208 feat: add opt-in intelligence auto fetch (#1913)
* feat: add opt-in intelligence auto fetch

* fix(review-feedback-1913): waiting for or sharing the in-flight refresh result instead of

* fix(review-feedback-1913): 补齐 workflow 显式映射,或在文档/PR scope 中明确该开关暂不适用于仓库自带默认 workflow

* docs: clarify intelligence auto fetch workflow scope

* fix(review-feedback-1913): 修复自动刷新读取全局配置而非当前分析配置的问题
2026-07-04 15:03:05 +08:00
Tom
2585f8ab92 update anspire info (#1915)
Co-authored-by: xiaowei <4775987@qq.com>
2026-07-04 14:42:25 +08:00
zhulinsen
8ff8124990 fix: speed up portfolio snapshot loading (#1914) 2026-07-04 12:10:41 +08:00
zhulinsen
a3e1b9e3ba fix: normalize watchlist separators (#1912) 2026-07-04 11:57:43 +08:00
zhulinsen
1ed0d34496 fix: normalize desktop wildcard bind hosts (#1901)
* fix: normalize desktop wildcard bind hosts

* fix(review-feedback-1901): 修正 docs/CHANGELOG.md 中与本 PR 无关/疑似已发布条目的范围漂移

* fix: address PR 1901 review feedback

* fix: remove stale changelog entries from PR 1901
2026-07-04 10:49:55 +08:00
zhulinsen
35e16b0c6f fix: handle incomplete Agent streams (#1899)
* fix: handle incomplete agent streams

* docs: trim changelog for agent stream fix
2026-07-04 09:45:21 +08:00
zhulinsen
282efa18e1 fix: preserve zero sentiment score alignment (#1900)
* fix: preserve zero sentiment score alignment

* fix(review-feedback-1900): 修正 docs/CHANGELOG.md 中与本 PR 无关的条目,避免把未包含在当前 diff 的功能/修复写入本 PR and
2026-07-04 09:23:18 +08:00
zhulinsen
77911efbc5 docs: prepare v3.25.0 changelog v3.25.0 2026-07-03 21:05:03 +08:00
zhulinsen
afbab3e717 fix: honor WEBUI_HOST for desktop backend binding (#1897)
* fix desktop WebUI host binding

* fix desktop dotenv host parsing
2026-07-03 21:01:22 +08:00
zhulinsen
a52c8502d7 fix: harden AlphaSift timeout handling (#1898) 2026-07-03 21:00:12 +08:00
zhulinsen
83b8154d0a fix: 评分建议过度归为持有,需收敛 hold/watch/buy/sell… (#1885) (#1887)
* fix(issue-1885): [bug]-评分建议过度归为持有,需收敛-hold/watch/buy/sell

* fix(review-feedback-1887): 澄清/修正评分与 action 的契约一致性问题,并补齐高风险路径的验证说明

* fix(review-feedback-1887): 补一句排除说明,避免和 AGENTS 对外部依赖/运行时配置变更需说明兼容、迁移与回退路径的要求产生歧义

* fix(review-feedback-1887): CI 当前未通过:结构化事实显示 backend-gate:failure,PR 描述中的本地验证也写明 test:TIMEOUT
2026-07-03 20:24:13 +08:00
zhulinsen
1a06568e4e fix: add jp kr closing auction phase windows (#1875) 2026-07-03 20:14:17 +08:00
zhulinsen
d70af7eafb fix(issue-1894): [bug]-回测时获取数据异常 (#1895) 2026-07-03 19:53:31 +08:00
Shlok Goyal
5a6c08b5f1 feat: 添加钉钉机器人支持 (Add DingTalk Notification Support) (#1878)
* feat: 添加钉钉机器人支持

* fix: chunk DingTalk payloads over the webhook limit

* docs: fix changelog format and update full-guide for DingTalk

* fix: reserve 1KB budget for DingTalk JSON payload overhead and add chunking unit tests

* test: add strict json payload byte assertion for DingTalk limits and truncate titles

---------

Co-authored-by: zhulinsen <42829555+ZhuLinsen@users.noreply.github.com>
2026-07-03 19:47:07 +08:00
sh1water
116d09e727 feat(agent): standardize stream progress events (#1871)
* feat(agent): standardize stream progress events

* docs(agent): document stream progress events

* docs: sync changelog with upstream main

* fix(web): render failed agent stages as non-success

* fix(agent): align stream stage lifecycle

* test(agent): stabilize timeout stream event clock

* fix(agent): split budget skip stream event

* docs(agent): document budget skip stream event

---------

Co-authored-by: Hzf <huangzhenfan666@163.com>
2026-07-03 19:37:51 +08:00
Alfred
7b39b73b9d feat: add generation backend status diagnostics (#1883) 2026-07-03 19:34:43 +08:00
zhulinsen
a47952047f [autocode] fix: format market review metrics (#1880)
* fix: format market review metrics

* fix(review-feedback-1880): 收敛 changelog 的无关变更,并补齐受影响页面/测试入口的一致性验证

* fix: format market review metrics consistently

* fix(review-feedback-1880): 澄清外部模型/API 兼容风险提示来源,或补齐对应官方依据、运行时兼容验证、迁移/回退路径
2026-07-03 19:34:10 +08:00
zhulinsen
52afa95103 docs: 更新台股支持文档入口 (#1884)
* docs: update Taiwan stock support docs

* docs: simplify README market coverage
2026-07-02 22:50:02 +08:00
Alfred
2e4c03e52d feat: add decision signal reassess preview (#1877) 2026-07-02 18:56:08 +08:00
Wenyu Chiou
0f57e4e2e5 fix(data): parse yfinance dividends from the single-column DataFrame yfinance 1.2.x returns (#1867)
yfinance 1.2.x returns Ticker.dividends as a single-column DataFrame instead of a
Series. YfinanceFundamentalAdapter iterated it with `.items()`, which for a DataFrame
yields (column_name, Series) — so `_safe_float(Series)` returned None, every dividend
event was dropped, and the TTM cash/count silently fell back to
`info.trailingAnnualDividendRate` (e.g. 24.0 with "0 次") instead of the true TTM sum.
Coerce to a Series before iterating.

Affects every yfinance-backed market (US/HK/JP/KR/TW); surfaced on a live TW report
(2330.TW showed 24.0 / 0 payouts vs the real ~22 across 4). + a regression test that
feeds a single-column DataFrame and asserts the events + TTM sum are parsed.

Co-authored-by: zhulinsen <42829555+ZhuLinsen@users.noreply.github.com>
2026-07-02 18:52:08 +08:00
Alfred
48b9e18a5f fix: relax opencode static output instruction (#1876) 2026-07-01 22:31:38 +08:00
zhulinsen
078aa1616d fix: sync desktop backend port (#1872) 2026-07-01 19:56:25 +08:00
Wenyu Chiou
9433f610cc fix(market-phase): detect the tw closing auction (13:25-13:30) (#1869)
_CLOSING_AUCTION_WINDOW_MINUTES had no tw entry, so `.get(market, 0)` gave a
zero-width window and infer_market_phase("tw") could never return CLOSING_AUCTION:
the last tick before 13:30 stayed INTRADAY and 13:30 flipped straight to POSTMARKET.

TWSE/TPEx run a 5-minute closing call auction (13:25-13:30), so add "tw": 5.
+ a phase-boundary regression test (no lunch break, 13:30 half-hour close):
13:24 INTRADAY / 13:25-13:29 CLOSING_AUCTION / 13:30 POSTMARKET.
2026-07-01 19:11:55 +08:00
Wenyu Chiou
7230465da5 feat(market): v2.1 — surface tw 三大法人 in report + LLM prompt, fix TWD currency (Refs #1777) (#1866)
* feat(market): v2.1 — consume tw 三大法人 in report + LLM prompt, fix TWD currency label

The merged 三大法人 (institutional flows) data (#1829/#1841/#1855/#1863) reached
get_fundamental_context but was never surfaced: the report renderer and the LLM
prompt-builder never read the institution block, so a real analysis run showed a tw
report with no 三大法人 figures. This wires the last mile (tw-only, additive,
fail-open) and fixes a TWD currency mislabel found in the same run:

- report render (src/notification.py): _append_institutional_flow renders a 三大法人
  net-buy/sell table (外资/投信/自营/合计 in 万股/亿股) when the institution block is
  status='ok'; _get_fundamental_blocks now extracts it. + zh/en/ko labels.
- LLM prompt (src/analyzer.py): _format_prompt injects a 三大法人 section (raw net
  figures + a qualitative 台股筹码过滤器 note, mirroring the capital_flow section)
  when status='ok' and all four core nets are present.
- fetch availability (data_provider/base.py): the tw institution fetch (a ~4-5s
  whole-market download) now uses the remaining stage budget instead of the ~3s
  per-symbol fetch cap that starved it and made the first/only stock of a run
  coin-flip to not_supported. Still bounded by the stage deadline (fail-open).
- currency (src/notification.py): _CURRENCY_SUFFIX gains TWD -> 新台币 so TWD amounts
  (revenue/profit/dividend) no longer render as the A-share default 元 (reads as RMB).

Verified end-to-end via a real analysis run: the tw report now shows the 三大法人
table and 新台币-labelled financials, and institution is reliably 'ok' on a
single-stock run. Strictly additive — cn/hk/us/jp/kr byte-identical (gated on
market=='tw' / status=='ok'); no capital_flow_signal / scoring / schema. + 11 tests.

Dual review (code-reviewer APPROVE + silent-failure-hunter): the hunter caught a
prompt-gate asymmetry (only total_net checked vs all four in the render gate);
tightened to require all four core nets, matching the render/base.py gate.

* fix(market): honour FUNDAMENTAL_FETCH_TIMEOUT_SECONDS=0 for the tw institution fetch

Review on #1866: the v2.1 institution-timeout change (use the remaining stage budget
instead of the ~3s per-fetch cap) inadvertently bypassed the existing
FUNDAMENTAL_FETCH_TIMEOUT_SECONDS=0 semantic — with fetch_timeout=0, valuation and
bundle are disabled (they gate on fetch_timeout) but the institution fetch still ran.

Gate the institution fetch on `fetch_timeout > 0` as well, so fetch_timeout=0 disables
it like the other fundamental fetches; when enabled it still uses the remaining stage
budget (the whole-market download needs more than the per-symbol cap). + a regression
test asserting fetch_timeout=0 -> institution not_supported and the fetcher is not called.

---------

Co-authored-by: zhulinsen <42829555+ZhuLinsen@users.noreply.github.com>
2026-07-01 19:11:27 +08:00
Wenyu Chiou
b889523396 feat(market): harden tw institutional fetcher — circuit breaker + TPEx date guard (#1864)
Two tw-only, strictly-additive, fail-open hardening changes to TwInstitutionalFetcher
(benchmarked against docs/data-source-stability.md):

- C1 circuit breaker: reuse data_provider.realtime_types.CircuitBreaker (the same class
  DataFetcherManager uses), keyed per market (twse/tpex), 3-fail / ~5-min cooldown /
  half-open probe. When an endpoint is unreachable the fetch is skipped fast and fails
  open, instead of paying timeout + throttle on every stock during an outage. The breaker
  tracks REACHABILITY: a hard network/HTTP error trips it; an empty / stat!=OK body still
  means the endpoint responded, so it counts as success (resets the failure streak and
  closes the breaker during recovery -- a no-data day mid-recovery can never strand it open).
- C2 TPEx date guard: TPEx OpenAPI serves only the latest trading day; an explicit date
  that does not match the served record now fails open (None) instead of a wrong-day record.

Tests: +6 (breaker opens after 3 failures & skips the 4th fetch; recovers after cooldown;
3 empties don't trip it; TPEx date match / mismatch / no-date). + CHANGELOG.

Dual review (code-reviewer APPROVE + silent-failure-hunter): the hunter flagged a
HALF_OPEN-recovery edge in the shared CircuitBreaker; resolved tw-side by treating an
empty response as success (reachability), without modifying the shared class.
2026-07-01 19:10:45 +08:00
zhulinsen
fc895e3124 fix: 提升 Discord 长报告分片发送可靠性 (#1861)
* fix: improve Discord long report delivery

* fix(review-feedback-1861): Catch all requests exceptions per chunk
2026-07-01 19:07:52 +08:00
Alfred
4c678850e2 feat: add Claude Code and OpenCode generation backends (#1850)
Co-authored-by: zhulinsen <42829555+ZhuLinsen@users.noreply.github.com>
2026-06-30 22:33:02 +08:00
Wenyu Chiou
b939f7579f feat(market): surface tw 三大法人 in the tw report institution block (Refs #1777) (#1863)
* feat(market): surface tw 三大法人 (institutional flows) in the tw report institution block

Wire the merged TwInstitutionalFetcher (#1829/#1841/#1855) into the tw analysis
report: in _build_offshore_fundamental_context, for market == "tw" only, the
institution block now carries the raw 三大法人 net buy/sell figures (foreign /
trust / dealer / total, unit=shares) from TWSE T86 / TPEx instead of the hardcoded
not_supported. v2 scope confirmed by the maintainer on issue #1777.

- tw-only + strictly additive: cn/hk/us/jp/kr offshore flows are byte-identical
  (the not_supported loop just excludes institution; non-tw still gets the same
  not_supported block). Pinned by tests for us/hk/jp/kr.
- fail-open + default-on: any error or no-data -> not_supported, never interrupts
  the analysis. Wiring (import/construct) failures log at error (visible) but still
  fail open; fetch failures log at warning.
- status "ok" only when all four core nets are present (a genuine 0 is kept).
- raw figures only: no capital_flow_signal / scoring / weight / schema / Web.

Tests: tests/test_tw_institution_report_wiring.py (9) covers data->ok, genuine-zero,
None/raise/init-raise fail-open, missing-core-net->not_supported, us/hk/jp/kr
byte-identical + fetcher-unused, and no-derived-key. + CHANGELOG.

Dual review (code-reviewer + silent-failure-hunter): the hunter caught the combined
try swallowing wiring (import/construct) errors silently at info -> split into
loud-but-fail-open (error log + still not_supported, honoring #1777's
never-interrupt rule) and guarded "ok" against a null core net.

* fix(market): address Codex review on tw institution wiring (#1863) — stage timeout, overall status, docs

- P1: run the tw institution fetch under the fundamental stage/fetch budget via
  _run_with_retry (like the other offshore blocks), so a slow / rate-limited TWSE/TPEx
  call fails open at the deadline instead of pushing the analysis past it.
- P2: count a present tw institution toward the OVERALL fundamental status so a report
  with only 三大法人 data still surfaces fundamentals (consumers key off the top-level
  status). missing_fields keeps the original three blocks, so offshore markets without
  institution data stay byte-identical.
- P2 (docs): sync docs/market-support.md (drop the now-false "data-layer only / not
  wired into report" clause) + add a tw institution note to docs/full-guide.md and
  docs/full-guide_EN.md (AGENTS.md requires user-visible report changes to update guides).

Tests: + stage-timeout (a 2s fetch is abandoned at the ~0.3s budget, fail-open) +
overall-status surfacing assertion. 10 tw-wiring tests + offshore/tw/jp-kr suites green.
2026-06-30 22:31:56 +08:00
zhulinsen
3080aa5c60 fix: 修复设置页分类切换辅助卡片残留 (#1851)
* fix: scope settings helper cards to categories

* fix(review-feedback-1851): 澄清结构化检测命中的外部模型/API 与运行时配置迁移风险是否为误报
2026-06-30 19:15:51 +08:00
Alfred
6cd64dc382 fix: surface Codex CLI desktop backend path diagnostics (#1857)
Co-authored-by: zhulinsen <42829555+ZhuLinsen@users.noreply.github.com>
2026-06-30 19:07:05 +08:00
Wenyu Chiou
e80038009b test(tw): live-network drift smoke + network-marked tests for 三大法人 fetcher (#1855)
* test(tw): add live-network drift smoke + network-marked tests for 三大法人 fetcher

The offline tests (tests/test_tw_institutional_fetcher.py) pin the parser to
frozen fixtures, so they cannot notice an upstream TWSE T86 / TPEx feed change.
Add two additive, tw-only drift detectors that hit the real public endpoints:

- tests/tw_institutional_live_smoke.py: manual non-pytest smoke (mirrors
  tests/longbridge_live_smoke.py). Checks endpoint liveness + core-column-name
  presence, and cross-checks the fetcher's foreign/trust/dealer/total against
  the raw columns plus the always-true reconstruction
  total == foreign + foreign_dealer + trust + dealer (the 3-term identity only
  holds when the foreign-dealer sub-component is 0).
- tests/test_tw_institutional_network.py: @pytest.mark.network, run only by the
  non-blocking Network Smoke cron (pytest -m network); the blocking backend gate
  runs pytest -m "not network" (scripts/ci_gate.sh) so these never gate a PR.
  Two self-contained tests cross-check the fetcher against the raw feed.

No production code touched (data_provider/base.py unchanged); fail-open and
no-silent-pass preserved. A renamed core/foreign-dealer column or a non-JSON
response (maintenance page / URL migration) is reported LOUD as drift; only a
transport error or non-trading-day soft-skips. Verified live against today's
feeds and via a negative-path simulation of every drift/transient case.

Dual review (code-reviewer APPROVE + silent-failure-hunter PROCEED) caught and
fixed soft-skip paths that had masked feed drift (non-JSON body swallowed as a
blip; foreign-dealer rename fabricated via `or 0`).

* test(tw): fail loud when a stock is present in the raw feed but the fetcher returns None

Addresses the review correctness-blocker on #1855. The TWSE/TPEx drift tests
called the fetcher first and soft-skipped on a None result as "transient /
suspended" WITHOUT checking the raw feed — so an upstream parse-prerequisite
drift (e.g. a 民國->ISO date-format change that _parse_tpex_row / _parse_t86_row
cannot convert) would make get_institutional_net() fail-open to None and be
silently skipped, the exact fail-open these tests exist to catch (and contrary
to the PR's stated "民國->ISO date switch fails loud").

Reorder both the smoke and the network tests: resolve the target stock's raw
row FIRST, then if the fetcher returns None — fail LOUD when the row IS present
in the raw feed (parse/date drift), and only soft-skip when the row is genuinely
absent (non-trading day / suspended / transient).

Verified: a negative-path simulation (raw row present + an unconvertible payload
date) now reports drift and fails, the live happy path still passes, and the
network tests are stable across repeated runs (transient blips hit both the raw
fetch and the fetcher together -> consistent skip, never a false fail).

---------

Co-authored-by: zhulinsen <42829555+ZhuLinsen@users.noreply.github.com>
2026-06-30 19:05:25 +08:00
zhulinsen
fa46038a93 fix(issue-1853): [bug]-在网页端点击“立即执行一次”后后台线程因缺少-`stock_code (#1854) 2026-06-30 19:04:32 +08:00
HyunRyeol Park
043c60378e feat: 报告输出语言新增韩语支持 (Korean report language, ko) (#1614) (#1844)
* feat(i18n): add Korean to report language label maps

Extend the report language layer with a third code `ko` so reports can
render deterministic labels in Korean. Adds `ko` to the supported list,
aliases (korean/kr/ko-kr), every translation map, the full report label
set, sentiment bands, the config registry enum and `.env.example`.
`zh`/`en` behavior is unchanged and unknown languages still fall back to
the default. Prompt and Web surfaces follow in later changes.

Refs #1614

* feat(i18n): emit Korean output directives in analysis prompts

Make the analysis and market-review prompts produce Korean output when
REPORT_LANGUAGE=ko. The decision agent now appends a Korean
output-language directive (JSON keys and decision_type enum unchanged),
and the market-review prompt reuses the English structural scaffolding
while instructing the model to write the shell, headings and conclusion
in Korean. Market-phase and context-pack prompt sections route ko to the
English structural base. The market-review payload keeps the truthful
language code via a dedicated output-language helper, leaving zh/en
behavior unchanged.

Refs #1614

* fix(i18n): localize phase and market-context guardrails for Korean

Route Korean reports through the English structural scaffolding for
market-phase and market-context prompt sections, and add Korean output,
detection markers, negations and recap patterns to the phase-decision and
daily-market-context guardrails so they operate on Korean model output.
Confidence and operation labels now flow through the shared localize
helpers. zh/en behavior is unchanged.

Refs #1614

* feat(i18n): localize Korean fallback output across analysis pipeline

Add Korean output to the deterministic strings emitted outside the LLM:
per-stock and executor output-language directives, no-API-key / backend
/ parse error fallbacks, hold-watch advice and reasons, market-review
titles and summaries, and history and notification report labels. Fund
flow, trend and confidence values now flow through the shared localize
helpers, and language-keyed advice tables no longer raise KeyError for a
third language. Structural prompt sections route ko to the English
scaffolding. zh/en output is unchanged.

Refs #1614

* feat(web): add Korean report language rendering

Extend the Web ReportLanguage type with ko and add Korean copy to the
report detail surfaces: report text, sentiment labels, market-phase
labels, analysis-context summary, market-review view, diagnostics and
news source. Run-flow chrome that is keyed by UI language falls back to
English for ko. The report-language selector is driven by the backend
config schema, so Korean appears automatically. zh/en rendering is
unchanged.

Refs #1614

* docs(i18n): document Korean report language support

Note that REPORT_LANGUAGE accepts ko in the bilingual guides and the
analyze / market-review request-language parameters, and add a
CHANGELOG entry for Korean report output.

Refs #1614

* fix(i18n): canonicalize Korean values and accept ko in API schemas

Add Korean aliases to the operation-advice, trend, confidence, chip and
bias canonical maps so Korean model output (매수/매도/보유/관망 etc.)
resolves to the correct decision_type and signal level instead of
falling back to hold or a score-band signal. Accept ko in the
analyze, market-review and decision-signal request schemas (and the
static API spec) so the typed client and backend agree and per-request
Korean analysis is not rejected with 422.

Refs #1614
2026-06-30 19:02:46 +08:00
Wenyu Chiou
2a65384654 perf(market): coalesce concurrent tw-institutional fetches (cache-stampede guard) (#1841)
Hardens the merged #1777 TwInstitutionalFetcher. Under concurrent callers for the
same (market, date) the previous check-then-fetch could issue N duplicate upstream
requests -- which for the TWSE T86 RWD endpoint risks tripping its informal
~3 req/5s ban. A per-(market,date) in-flight lock now coalesces same-key callers
into a single fetch (double-checked against the cache); different keys still fetch
in parallel, and the master lock is never held across network I/O.

- data_provider/tw_institutional_fetcher.py: per-key in-flight lock + _read_cache /
  _key_lock helpers. Behavior is otherwise unchanged -- still fail-open, still
  caches only non-empty results, tw-only, no data_provider/base.py change.
- tests: + concurrent-same-key-coalesces-to-single-fetch (8 threads -> 1 request),
  different-keys-not-coalesced, and HTTP-error (429) fail-open
- docs/CHANGELOG.md: [改进] entry

Refs #1777

Co-authored-by: zhulinsen <42829555+ZhuLinsen@users.noreply.github.com>
2026-06-30 19:01:38 +08:00
zhulinsen
9bd1604f2c fix: 稳定展示关联板块模块 (#1836)
* fix: stabilize related board rendering

* fix(review-feedback-1836): Recognize existing Chinese sector tables before appending

* fix(review-feedback-1836): Use unique segment keys for combined reviews

* fix(review-feedback-1836): return or otherwise propagate the rendered markdown for the merge path

* fix(review-feedback-1836): Insert sector fallback inside each market segment

* fix: preserve market review segment boundaries
2026-06-30 18:58:07 +08:00
zhulinsen
a448886f67 fix: restore stock bar summary badges (#1848) 2026-06-29 21:18:02 +08:00
ZhuLinsen
a62fc56a74 fix: restore installable longbridge constraints v3.24.1 2026-06-28 21:29:18 +08:00
ZhuLinsen
dbfd8c1fb8 chore: prepare v3.24.0 release v3.24.0 2026-06-28 21:08:26 +08:00
zhulinsen
29fa05049d fix: harden AlphaSift source stability (#1832)
* fix: harden AlphaSift source stability

* docs: add data source stability diagrams

* fix(review-feedback-1832): Handle degraded EastMoney failures for the new default

* fix: allow JP KR market light snapshots

* fix(review-feedback-1832): 补充覆盖 alert 创建/校验路径的回归测试,证明 JP/KR 不会被告警路径接受
2026-06-28 20:23:02 +08:00
zhulinsen
3fddbd8fbc fix: clarify JP KR service boundaries (#1823)
* feat: add JP KR market review support

* fix: clarify JP KR service boundaries

* fix(review-feedback-1823): add the fields to the response schema and cover the endpoint path, not

* fix(review-feedback-1823): Avoid routing JP/KR reviews through MarketLight schema

* fix(review-feedback-1823): add JP/KR to that resolver when accepting these values

* fix(review-feedback-1823): Keep JP/KR daily contexts from normalizing to CN and add JP/KR labels

* fix(review-feedback-1823): 解决冲突后再合入

* fix(review-feedback-1823): 解决冲突并确认最终 diff 后再评审合入

* fix(review-feedback-1823): 澄清或补齐验证证据

* fix(review-feedback-1823): 解决冲突,并在冲突解决后的 head 上重新确认关键验证结果

* fix(review-feedback-1823): Make the Chinese JP/KR prompt shell region-aware

* fix(review-feedback-1823): 解决冲突后再判断最终 head 是否可合入

* fix(review-feedback-1823): 基于目标分支解决冲突,并在冲突后的最终 diff 上重新确认相关后端/Web 检查

* fix(review-feedback-1823): 修复

* fix(review-feedback-1823): 解决冲突

* fix(review-feedback-1823): 解决冲突后再合入

* fix(review-feedback-1823): 解决冲突后再合入

* fix(review-feedback-1823): Make the all-markets checkbox exclusive

* fix(review-feedback-1823): 解决冲突,并在冲突解决后的最新 head 上重新确认关键测试和 Web 构建结果

* fix(review-feedback-1823): 解决冲突并确保解决后的 head 重新通过对应验证

* fix(review-feedback-1823): 解决冲突,并在冲突解决后重新确认受影响的后端、Web 与文档改动仍一致

* fix(review-feedback-1823): 解决冲突,再基于最新 base 复核完整 diff,并重新确认相关后端/Web 验证结果仍成立

* fix(review-feedback-1823): 解决冲突后重新确认最终 diff 与 CI 结果

* fix(review-feedback-1823): 收敛

* fix(review-feedback-1823): 基于目标分支解决冲突并重新确认关键验证结果

* fix(review-feedback-1823): 解决

* fix(review-feedback-1823): 收敛

* fix(review-feedback-1823): 解决冲突后重新确认 diff 与 CI

* fix(review-feedback-1823): 补充本次未改变哪些配置契约、对应测试覆盖和回退方式

* fix(review-feedback-1823): 收敛

* fix(review-feedback-1823): PR 描述与实际 diff scope 仍不完全对齐:完整改动包含

* fix(review-feedback-1823): 解决冲突并在冲突后的最终 diff 上重新确认 CI/关键测试结果

* fix(review-feedback-1823): 解决冲突并确认解决后的 diff 与现有 43 个文件 scope 仍一致

* fix(review-feedback-1823): 解决冲突后再合入

* fix(review-feedback-1823): 解决冲突,并在最终 head 上重新确认受影响的后端与 Web 验证结果

* fix(review-feedback-1823): 解决冲突并确认冲突解决后的最终 head 仍通过对应验证

* fix(review-feedback-1823): 处理旧 both 历史记录在 JP/KR 复盘上下文匹配中的语义兼容风险
2026-06-28 18:53:39 +08:00
Wenyu Chiou
7715896fe4 feat(market): tw institutional-flows (三大法人) data-layer fetcher (#1829)
Implements the #1777 maintainer-greenlit Phase-2 data layer: a self-contained,
tw-only fetcher for Taiwan per-stock institutional (外資/投信/自營商) net
buy/sell. Strictly additive -- no change to the existing cn/hk/us/jp/kr flows in
data_provider/base.py, and not yet wired into the report/Web/scoring path (a
deliberate follow-up per the maintainer's scope).

- data_provider/tw_institutional_fetcher.py (NEW): TwInstitutionalFetcher
  - 上市 .TW  -> TWSE T86 legacy rwd JSON endpoint (西元 date, comma values)
  - 上櫃 .TWO -> TPEx OpenAPI tpex_3insti_daily_trading (民國 date, plain ints)
  - T86 columns are read by NAME (validated against the payload `fields` header),
    so a TWSE column rename / reorder fails open instead of silently shipping
    misaligned numbers under stale indices
  - foreign_net = 外陸資 (ex 外資自營商, T86) / dealer-excluded foreign (TPEx) so
    the breakdown matches the official 三大法人 total; total_net is the official
    figure; unit = shares, signs preserved
  - whole-market single-day cache keyed by (market, date), filtered per stock;
    ~3 req/5s throttle (own lock) for the T86 endpoint
  - fail-open: any network/rate-limit/empty/unknown-stock returns None; a missing
    or renamed column drops the row (never a fabricated 0); a row whose trading
    date cannot be attributed (TPEx 民國 unconvertible) is dropped; empty/failed
    fetches are not cached (no TTL-long blackout)
- tests/test_tw_institutional_fetcher.py (NEW): 20 offline tests with fixtures
  trimmed from real T86 (2330) / TPEx (3105) responses; pins the net breakdown +
  sign, 民國->西元 conversion, routing, caching, and fail-open -- including
  column reorder (parsed by name), column rename / missing header (fail-open),
  the missing-column-vs-genuine-zero distinction, and unconvertible TPEx dates
- docs/market-support.md + docs/CHANGELOG.md: data-source capability boundary +
  OGDL v1 license note; no new config (.env.example untouched)

Addresses the #1829 review (read T86 by field name; drop TPEx rows with an
unconvertible date; foreign_net excludes foreign-dealers).

Sources are 政府開放資料 under 政府資料開放授權條款第 1 版 (OGDL v1, commercial-safe).

Refs #1777
2026-06-28 18:49:09 +08:00
zariba
94cd2a4d96 feat(data): 接入 TickFlow 核心 A 股数据源 (#1790)
* feat(data): integrate TickFlow core A-share provider

* fix(data): harden TickFlow daily kline contract

* fix(web): localize TickFlow settings and run-flow coverage

* fix(web): clarify TickFlow priority settings

* chore(deps): require verified TickFlow SDK

---------

Co-authored-by: timeance <timeance@users.noreply.github.com>
2026-06-28 17:09:28 +08:00
zhulinsen
ade3b4cb6e feat: add JP KR market review support (#1822)
* feat: add JP KR market review support

* fix(review-feedback-1822): update the Market Light schema/service support before accepting these

* fix(review-feedback-1822): add JP/KR to daily market context before accepting them and update

* fix(review-feedback-1822): add English JP/KR strategy text or make the renderer language-aware

* fix(review-feedback-1822): update the prompt role/shell alongside the new accepted regions

* fix(review-feedback-1822): 修正 PR 描述中的过期验证结论,并补充/澄清 JP/KR Yahoo Finance 指数兼容性证据或在线验证边界

* fix(review-feedback-1822): 收敛 Market Light 告警契约与用户文档同步问题

* fix(review-feedback-1822): 修正后再合入

* fix(review-feedback-1822): 补齐外部 Yahoo Finance 指数接入与运行时配置变更的兼容性/迁移证据,并修正 PR 描述中与当前 CI 状态不一致的内容

* fix(review-feedback-1822): 当前 CI 状态为 failure,且阻断型 backend-gate 失败

* fix(review-feedback-1822): 修复 MARKET REVIEW REGION 逗号值在交易日过滤与配置 schema 中的契约漂移,并补充对应回归测试

* fix(review-feedback-1822): 收敛 PR 描述中的验证状态与用户可见 Web 改动证据

* fix(review-feedback-1822): 修正 PR 描述中的过期验证结论,并补充 Web 设置变更的截图或无法截图时的替代可视证据说明

* fix(review-feedback-1822): 收敛 PR 描述中的验证状态,并补齐 Web 设置变更的截图或替代可视证据

* fix(review-feedback-1822): 收敛 PR 描述后再合入

* fix(review-feedback-1822): 收敛 PR 描述中的验证状态,并补充 Web 设置变更截图或无法截图时的替代可视证据说明

* fix(review-feedback-1822): 收敛验证状态和 Web UI 可视证据,避免合入记录与实际 head 不一致

* fix(review-feedback-1822): 收敛 PR 描述中的验证状态与 Web 可视证据

* fix(review-feedback-1822): 收敛 PR 描述中的验证状态,并补齐 Web 设置变更的截图或替代可视证据说明

* fix(review-feedback-1822): 修正 PR 描述与当前 CI 事实不一致的问题,补充 Web 设置可视证据,并收敛或拆出 PR 模板改动

* fix(review-feedback-1822): 收敛 PR 描述与证据

* fix(review-feedback-1822): 修正 PR 描述与证据,使验证状态、用户可见变更证据、模板改动范围和当前 head 保持一致

* fix(review-feedback-1822): 收敛 PR 描述、补齐可视证据,并澄清/补充外部模型/API 与运行时配置迁移相关兼容性证据

* fix(review-feedback-1822): 收敛 Web/文档契约不一致、同步残留测试,并更新 PR 描述与可视证据
2026-06-28 17:03:15 +08:00