33 Commits

Author SHA1 Message Date
Elvis Wang
eb1333a678 feat: 支持通过 --stocks 一次性分析板块指数 (#2300)
* feat: add one-shot index analysis via --stocks with structured AnalysisTarget pipeline

* fix: render index data sources in aggregate reports

* fix: refresh index registry before --stocks parsing and filter indices on CN holidays

---------

Co-authored-by: zhulinsen <42829555+ZhuLinsen@users.noreply.github.com>
2026-08-28 21:56:48 +08:00
zhulinsen
8052d1a0ac ci: accelerate selective test gates (#2158) 2026-08-05 19:14:40 +08:00
zhulinsen
91988da149 feat: 添加报告分享图片与 Web 一键分享 (#2146)
* feat: add report image sharing

* fix(review-feedback-2146): 评审结论 - 代码检查 :当前整个 PR 仍有 2 个未关闭的高置信度代码 blocker。最新复核摘要:基于 merge-base

* fix(review-feedback-2146): preserve the Markdown fallback for unavailable snapshots and preserve

* fix(review-feedback-2146): 补一组通知回归测试,至少覆盖

* fix(review-feedback-2146): 在源码树执行 npm ci 和 npx playwright install chromium,这与预编译 desktop 发行包环境不一致

* fix(review-feedback-2146): 评审结论 - 代码检查 :当前整个 PR 仍有 1 个未关闭的高置信度代码 blocker。最新复核摘要:基于 merge-base

* fix(review-feedback-2146): 补上明确的 CLI/Chromium 安装提示,避免当前日志和 503 文案继续把用户引向

* fix(review-feedback-2146): 补到与 docs/share-images.md 一致,直接提示 cd apps/dsa-web && npm ci 和 npx
2026-08-02 16:45:37 +08:00
xushengasd
5d98d6d787 feat(phase1): converge multi-strategy evidence contract (#2031)
Introduce the StrategyEngine facade and centralize deterministic opinion partitioning, aggregation, synthesis, and signal normalization.

Keep invalid opinions in diagnostics, protect synthesis ownership across fallback paths, and add localized strategy rendering for notification, history, Markdown, and WeChat outputs.

Harden legacy and malformed strategy_synthesis payload handling through shared renderer helpers, with public-entry regression coverage and an updated Phase 1 contract.

Co-authored-by: zhulinsen <42829555+ZhuLinsen@users.noreply.github.com>
2026-07-19 18:55:42 +08:00
zhulinsen
e8a9ca7742 fix: harden release packages and report market context (#1994)
* fix: bundle orjson in release packages

* fix: remove duplicate decision signal excerpts

* feat: add TickFlow sector ranking fallback
2026-07-12 18:56:21 +08:00
zhulinsen
093057a11b fix: 统一报告动作展示口径 (#1982)
* fix: unify report action display

* fix(review-feedback-1982): add Korean action labels or fall back before returning display action

* fix(review-feedback-1982): Derive signal metadata from resolved actions

* fix(review-feedback-1982): Derive history signal metadata from resolved actions

* fix(review-feedback-1982): Derive renderer emojis from resolved actions

* fix(review-feedback-1982): src/notification.py:2838:build stock summary 先得到 display

* fix(review-feedback-1982): 将 PR 正文同步到最新 head,确保范围、验证结果与实际 diff 一致

* fix(review-feedback-1982): 将 GitHub PR 正文同步到当前 head,并修正 docs/CHANGELOG.md 中不准确的审查过程记录
2026-07-11 14:04:34 +08:00
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
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
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
03fe7a00a9 feat: 补齐大盘报告与 Web 个股页的概念板块展示 (#1764) (#1778)
* feat(issue-1764): feat:-补齐大盘报告与-web-个股页的概念板块展示

* fix(review-feedback-1778): 确认历史报告 fallback 路径是否完整透传 conceptRankings,否则会出现新字段在部分历史详情/API 场景中静默丢失

* fix: render market review industry and concept rankings side-by-side

* fix: refine related board display and concept ranking cache
2026-06-27 23:07:18 +08:00
zhulinsen
688e980714 fix: show phase decision in default reports (#1807) 2026-06-27 16:46:10 +08:00
zhulinsen
0344901c6b fix: keep decision signal details out of summaries (#1781) 2026-06-24 21:51:32 +08:00
Alfred
dda5269123 fix: address P6 signal linkage gaps (#1724) 2026-06-19 23:04:52 +08:00
mumu
3153c764a4 fix: 收敛多股通知摘要的市场状态展示 (#1612)
* fix: compact aggregate report market status

* fix(review-feedback-1612): preserve input order when selecting market status

* chore: rerun review after clarifying PR scope
2026-06-05 22:47:39 +08:00
Alfred
9b76f8d240 feat: #1386 P6 联动告警、持仓和历史阶段摘要 (#1589)
* feat: link phase summaries across P6 surfaces

* fix: align portfolio analysis response status

* fix: stabilize backtest phase filtering

* fix: normalize portfolio analysis symbols
2026-06-04 09:17:39 +08:00
mumu
9178e03762 fix: improve notification report rendering (#1531)
* fix: improve notification report rendering

* fix: polish chat report rendering output

* fix: add chat-optimized report layout

* fix: use chat report for im image routing

* fix: adapt im report formatting per channel

* fix: make im reports decision cards

* chore: reserve notification renderer presets

* docs: trim notification rendering guidance

* fix(review-feedback-1531): preserve valid links but escape non-link Telegram Markdown characters

* fix(review-feedback-1531): Chunk Telegram fallback before sending raw text

* fix(review-feedback-1531): avoid stripping arbitrary leading whitespace here

* fix: preserve legacy notification report formatting

* fix(review-feedback-1531): 补齐外部模型/API 与运行时配置迁移命中的排除说明或兼容性证据
2026-05-31 19:45:12 +08:00
mumu
35f26bdc73 fix: 交互式消息只回对应渠道而非全局广播 (#1501) (#1502)
* fix(issue-1501): [feature]-飞书同时配置了两种推送方式的改进

* fix(review-feedback-1502): 补齐非飞书交互式上下文的处理与回归测试
2026-05-29 22:53:48 +08:00
TianleZhang
bb814ff89d feat: 邮件报告补充 财务摘要 / 股东回报 / 关联板块,并接入 HK/US 基本面 (#1369)
* feat: enrich email report with financial / dividend / related-boards blocks for CN/HK/US

Render three structured sections in single-stock and dashboard markdown reports
(used by email and other static channels) sourced from fundamental_context:

- 财务摘要: report date, revenue, parent net profit, operating cash flow, ROE,
  YoY growth, gross margin
- 股东回报: TTM cash dividend per share (pre-tax), TTM event count, TTM yield,
  latest ex-dividend date
- 关联板块: belong_boards with sector-leading/lagging signal & change_pct when
  available; auto-collapses to a 2-col (name / type) layout when no sector
  ranking data exists (typical for HK/US)

To unlock the offshore (HK/US) data path:

- Add YfinanceFundamentalAdapter producing the same bundle shape as the
  AkShare adapter, with growth, financial_report (incl. currency),
  TTM dividend events, and sector+industry as belong_boards
- Route get_fundamental_context for hk/us through a new
  _build_offshore_fundamental_context helper instead of short-circuiting
  to not_supported; keep capital_flow / dragon_tiger / boards as
  not_supported (no equivalent feed)
- Stop overwriting belong_boards in the pipeline for non-CN markets so the
  adapter-provided sector/industry data survives

Notification renderer:

- Attach fundamental_context onto AnalysisResult so the notification layer
  can reach it without an extra DB round-trip
- Currency-aware formatting: USD -> 亿/万美元, HKD -> 亿/万港元,
  CNY/other -> 亿/万元; per-share amounts get the same suffix
- Right-align numeric columns and center the report-date column in the
  financial summary and shareholder return tables for cleaner rendering

Tests:

- Offline coverage for the new yfinance adapter (symbol conversion, bundle
  shape, refusal to use QoQ as YoY, graceful degradation when yfinance is
  unavailable)
- Offshore market path through DataFetcherManager.get_fundamental_context
- Adaptive related-boards rendering (2-col when no sector signal,
  4-col when at least one row carries data)
- Currency-aware amount formatting for AAPL (USD) and HK09988 (CNY)

* fix: split financial vs dividend currency and recompute TTM yield for HK/US

HK ADRs typically report financialCurrency=CNY but pay dividends in HKD
(live yfinance confirms: 9988.HK / 0700.HK both have financialCurrency=CNY
and currency=HKD; BABA US ADR has financialCurrency=CNY and currency=USD).
Previously the adapter wrote a single currency field shared by both the
financial report and the dividend block, which rendered HK dividends as
yuan in the email report.

This change writes earnings.financial_report.currency from
info.financialCurrency and earnings.dividend.currency from info.currency
independently, and the notification renderer reads each block's own
currency (falling back to financial_report.currency when dividend.currency
is absent, which keeps AkShare A-share rendering unchanged).

TTM dividend yield was sourced from info.dividendYield, mixing the
numerator (TTM cash window) with a denominator-defined yield from a
different yfinance computation. The yield is now recomputed as
ttm_cash_dividend_per_share / latest_price * 100 with both sides in the
trading currency (latest_price falls through info.currentPrice ->
regularMarketPrice -> previousClose). info.dividendYield is now a
last-resort passthrough (no *100, since current yfinance already returns
percent), behind info.trailingAnnualDividendYield (decimal).

Docs (full-guide / full-guide_EN) updated: HK/US now returns
valuation/growth/earnings/belong_boards rather than not_supported, with
the dual-currency split and the TTM yield formula explicitly documented.
CHANGELOG entries rewritten to reflect the corrected behavior.

Verified live against 9988.HK / 0700.HK / AAPL / 600519: the rendered
email shows financial summary in 亿元 for HK ADRs (CNY statements) while
the shareholder return block shows 港元 (HKD dividends), and the
recomputed yields match ttm_cash / latest_price in the same currency.

---------

Co-authored-by: suan baby <suanai@tianle.me>
2026-05-21 20:04:32 +08:00
mumu
b7d449783c fix: 资金流数据缺失 (#1367) (#1368)
* fix(issue-1367): [bug]-资金流数据缺失

* fix(review-feedback-1368): preserve agent-provided chip data when prefetch is unavailable and

* fix(review-feedback-1368): 补充具体受影响文件/字段、是否会清理或迁移用户已有配置、用户可见恢复方式,以及对应回归测试或确认不涉及运行时行为的证据

* fix(review-feedback-1368): 结构化检测显示本 PR 涉及模型名、provider、Base URL、废弃日期、LiteLLM 或 LLM

* docs: trim issue 1367 compatibility notes

* docs: keep issue 1367 note in changelog only
2026-05-20 23:32:14 +08:00
Alfred
b43d636df1 feat: 记录告警通知结果与持久化冷却 P4 (#1337)
* feat: record alert notification attempts and cooldowns

* fix: address alert cooldown review feedback
2026-05-18 22:42:24 +08:00
mumu
e407b5bf14 feat: Add report LLM model visibility toggle (#1294) 2026-05-16 15:12:39 +08:00
Alfred
a75a0c502e feat: complete p6 notification channel cleanup (#1275) 2026-05-13 19:19:54 +08:00
Alfred
9f56238420 feat: 支持 ntfy 一等通知渠道(P6-A) (#1271)
* feat: add ntfy notification channel

* test: add ntfy smoke evidence images

* fix: validate ntfy endpoint in structured config

* fix: align ntfy endpoint validation
2026-05-13 12:47:46 +08:00
Alfred
9f70705234 feat: 添加 P4 通知降噪机制 (Refs #1200) (#1260)
* feat: add notification noise controls

* docs: clarify notification timezone fallback

* fix: address notification noise review feedback
2026-05-11 07:45:41 +08:00
Alfred
0adcef3627 feat: add notification routing strategy (#1248)
Co-authored-by: mumu <42829555+ZhuLinsen@users.noreply.github.com>
2026-05-10 13:24:02 +08:00
Alfred
f9549c7f39 fix: add notification baseline diagnostics (#1200) (#1205)
Co-authored-by: mumu <42829555+ZhuLinsen@users.noreply.github.com>
2026-05-06 18:46:35 +08:00
Xinyao Qiu
14d3b746fe feat: add Slack as a first-class notification channel (#747)
* feat: add Slack as a first-class notification channel

* fix: guard Slack image delivery with _should_use_image_for_channel()

* fix: require SLACK_CHANNEL_ID in workflow config check

* docs: add Slack channel entry to CHANGELOG and fix README_CHT nav link

* fix: use Slack new file upload API for image delivery

* fix: update Slack image test for new upload API, add slack to md2img example

* fix: send raw bytes to Slack upload URL and unify bot/webhook precedence

* docs: unify Slack Bot > Webhook precedence across all docs

* docs: add Slack config entries and setup guide to full-guide (zh/en)

Add SLACK_BOT_TOKEN, SLACK_CHANNEL_ID, SLACK_WEBHOOK_URL rows to both
config tables (GitHub Actions + local run) and a dedicated Slack setup
section with Bot-first precedence, mirroring the existing Discord
section structure. Applied to both full-guide.md and full-guide_EN.md.

* feat: register Slack config fields in config_registry for Web settings

Add SLACK_BOT_TOKEN, SLACK_CHANNEL_ID, SLACK_WEBHOOK_URL to
_FIELD_DEFINITIONS (display_order 36-38, between Discord and Pushover)
so /api/v1/system/config/schema and the Web settings page can expose
them. Add SLACK to _infer_category() notification prefix list.

New test file test_config_registry.py (6 cases) verifies field
registration, sensitivity flags, display ordering, and schema response
inclusion — prevents future channels from shipping without UI exposure.

* fix: use password control for SLACK_WEBHOOK_URL to prevent plaintext leak

SLACK_WEBHOOK_URL was marked is_sensitive=True but ui_control was text,
inconsistent with DISCORD_WEBHOOK_URL and other sensitive Webhook fields.
The Web settings page would display the URL in plaintext.

Also added a registry-wide regression test: any is_sensitive field must
use ui_control=password, preventing future channels from repeating this.
2026-03-20 11:41:09 +08:00
mumu
ef328e906b feat: add configurable report language (#764)
* feat: add configurable report language

* Fix review follow-ups for history and fallback localization

* fix: prefer .env report language at startup

* fix: address report language review feedback

* fix: address latest report language review feedback
2026-03-19 22:55:17 +08:00
Frank
a4a623da39 fix(notification): chunk oversized pushplus reports (#564) Fixes #489 2026-03-09 21:48:56 +08:00
Alfred
53e3d2dead [Feature] 报告引擎 P0:Schema、模板、完整性校验、Brief 模式、历史对比 (#560) (#561)
* chore(config): add report engine feature flags and template settings

* feat(analyzer): add pydantic schema validation for llm report json

* feat(report): report engine P0 - schema, templates, integrity, brief mode, history comparison

- Pydantic AnalysisReportSchema for LLM JSON validation
- Jinja2 templates (markdown, wechat, brief) with configurable dir
- Content integrity check with retry and placeholder fallback
- Brief mode (REPORT_TYPE=brief) for 3-5 sentence summary
- History comparison service for signal changes across runs
- generate_aggregate_report unified entry, ReportType.from_str(detailed)
- Config: REPORT_TEMPLATES_DIR, REPORT_RENDERER_ENABLED, etc.

Fixes #560
2026-03-09 21:35:55 +08:00
Alfred
c85423dfca [feat] 在分析报告中标记使用模型并完善展示链路 Issue #528 (#534)
* feat: mark model used in reports and notifications (#528)

* refactor: centralize model_used normalization and raw_result parsing (#528)

---------

Co-authored-by: mumu <42829555+ZhuLinsen@users.noreply.github.com>
2026-03-07 20:29:02 +08:00
Anthony Jiang
d5b8b60c69 refactor: formatter and notification (#516)
* fix: discord把超过0x10000的字符都计算为2个字

* refactor & perf: truncate_to_bytes and chunk_markdown_by_bytes are now slice_at_max_bytes and chunk_content_by_max_bytes, improved logic and performance for both, removed legacy truncate method in notification.py

* style: changed emoji_len to special_char_len for clarity

* refactor & perf: refactored formatters, combined and removed similar codes. Made chunk_content_by_xxx universal.

* fix: fixed a bug in wechatsender

* fix: bug in feishu_stream where wrong arguments for _send_interactive_card was used.

* fix: fixed a bug in formatters which can adds unexpected separators in chunked messages. fixed a bug where sleep timer was missed in wechat sender and feishu stream.

* test: added more tests

* perf: improved performance of _effective_len and _slice_at_effective_len

* fix: fixed a bug where  recursion was set incorrectly
2026-03-05 22:00:26 +08:00
Anthony Jiang
46a8af487d Notification refactorisation (#435)
* refactor: refactored notification.py; moved different send methods to dedicated sender classes, and static formatting methods to formatters.py

* fix: fixed missing import WECHAT_IMAGE_MAX_BYTES

* docs: added docstring

* test: added unit tests for notication.py
2026-02-28 16:21:40 +08:00