fix missing capital flow buy guard - #1289
Conversation
🤖 自动审查报告
📁 修改的文件
🧠 AI 代码审查意见结论Ready to Merge 结构化审查结果必要性通过 关联性通过 类型
描述完整性完整 风险级别低 必改项无 建议项
|
There was a problem hiding this comment.
Pull request overview
This PR fixes a decision-stability edge case where a direct buy recommendation could remain intact even when the capital-flow block exists but is unavailable/empty, leading to overconfident buy conclusions.
Changes:
- Adjust
stabilize_decision_with_structure()so that when capital flow is unavailable and the inferred decision is buy, the result is downgraded to hold/watch-only, with lowered confidence and a capped sentiment score. - Add a dedicated downgrade helper to populate dashboard/risk fields consistently for the “missing capital flow” buy-guard case.
- Update regression tests and changelog to reflect the new conservative behavior.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
src/analyzer.py |
Applies a stricter guard for buy signals when capital-flow data is unavailable, and introduces a dedicated downgrade helper. |
tests/test_decision_stability.py |
Updates assertions to expect buy downgrades (while preserving existing sell/unavailable behavior) and strengthens regression coverage. |
docs/CHANGELOG.md |
Documents the behavior change in the [Unreleased] section using the repo’s flat bullet format. |
Comments suppressed due to low confidence (1)
tests/test_decision_stability.py:217
- This test now expects a buy downgrade (decision_type="hold" and decision_stability.applied=True) when capital_flow.status is an unavailable variant, but the test name still says “skips_calibration…”. Consider renaming it to match the new downgrade behavior to avoid confusion.
assert buy_result.decision_type == "hold"
assert buy_result.operation_advice == "持有观察"
assert buy_result.dashboard["decision_stability"]["applied"] is True
| assert result.decision_type == "hold" | ||
| assert result.operation_advice == "持有观察" | ||
| assert result.dashboard["decision_stability"]["applied"] is True | ||
| assert "资金流数据缺失" in result.dashboard["decision_stability"]["capital_flow_status"] |
| status_text = _capital_flow_status_for_stability(flow_status, language) | ||
| if language == "zh": | ||
| advice = "持有观察" | ||
| reason = f"{status_text},买入结论缺少资金面确认,先按观察处理。" | ||
| signal_type = "🟡持有观望" | ||
| no_position = "空仓先不追买,等待资金流恢复、支撑确认或有效突破后再行动。" | ||
| has_position = "持仓以关键支撑为风控线,资金流恢复前控制仓位。" | ||
| confidence = "低" | ||
| else: | ||
| advice = "Hold and watch" | ||
| reason = f"{status_text}; the buy call lacks capital-flow confirmation, so treat it as watch-only." | ||
| signal_type = "🟡 Hold / Watch" | ||
| no_position = "Do not chase; wait for capital-flow recovery, support confirmation, or a valid breakout." | ||
| has_position = "Use key support as the risk line and keep position size controlled until capital flow recovers." | ||
| confidence = "Low" | ||
|
|
||
| result.decision_type = "hold" | ||
| result.operation_advice = advice | ||
| result.confidence_level = confidence | ||
| try: | ||
| score = int(getattr(result, "sentiment_score", 50)) | ||
| except (TypeError, ValueError): | ||
| score = 50 | ||
| result.sentiment_score = min(59, max(45, score)) | ||
|
|
ZhuLinsen
left a comment
There was a problem hiding this comment.
评审结论
- 必要性:通过。该 PR 针对资金流不可用时仍保留直接买入结论的问题,属于实际决策安全修复。
- 是否有对应 issue:有,Fixes #1286。
- PR 类型:fix,修改
src/analyzer.py的决策稳定性逻辑,并补充回归测试与 changelog。 - description 完整性:完整。已说明问题、根因、修复点、验证命令、风险和回滚方式,符合本仓库 AGENTS.md 对 fix 类 PR 的交付要求。
- 是否可直接合入:可。CI 已通过,改动范围聚焦,
docs/CHANGELOG.md已按[Unreleased]扁平格式补充记录;当前mergeable_state=blocked不单独构成阻断。
主要问题
- [Nice to have]
tests/test_decision_stability.py中仍有部分测试名使用skips_calibration...表述,但断言已经改为降级买入结论。该问题不影响运行时正确性,也不应阻断合入,但建议后续同步重命名,避免测试意图和当前行为不一致。
🤖 此回复由 OpenReview Bot 自动生成,仅供参考。如有疑问请 @维护者。
3abc092 to
204a6b0
Compare
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 204a6b0aad
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| decision_type = infer_decision_type_from_advice( | ||
| getattr(result, "decision_type", ""), | ||
| default=getattr(result, "decision_type", "hold") or "hold", | ||
| ) |
There was a problem hiding this comment.
Detect buy advice before skipping unavailable flow
When decision_type is hold or otherwise non-buy while the user-visible operation_advice still says 买入/Buy (the model returns both fields, and only missing decision_type is inferred from advice), this guard treats the result as non-buy and calls the unavailable-flow path, leaving the buy advice and high score unchanged despite missing capital-flow data. The unavailable-flow buy guard should reconcile or infer from operation_advice before deciding whether to skip the downgrade.
Useful? React with 👍 / 👎.
9e7fa99 to
732d846
Compare
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 4164b64ea5
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| if flow_bias == "unavailable": | ||
| if isinstance(fundamental_context, dict) and "capital_flow" in fundamental_context: | ||
| if decision_type == "buy" or advice_decision_type == "buy": | ||
| _downgrade_buy_without_capital_flow( |
There was a problem hiding this comment.
Preserve buys for markets without capital-flow support
When analyzing US/HK stocks or ETFs, DataFetcherManager still returns a capital_flow block with status: not_supported (for example data_provider/base.py:2142-2146 and 2339-2345), and the pipeline always passes that context into this guard. This new branch therefore downgrades every otherwise valid buy call for those supported markets solely because A-share capital-flow data is unavailable, even though that data source is not expected to exist there. Gate the downgrade to markets/data sources where capital flow is actually an applicable confirmation signal, otherwise non-CN/ETF reports can no longer produce buy recommendations.
Useful? React with 👍 / 👎.
Summary
Fixes #1286.
buyconclusions tohold/ watch-only when the capital-flow block exists but is unavailable or empty.selland non-buy conclusions.Root Cause
stabilize_decision_with_structure()previously skipped calibration when capital flow was unavailable. That meant abuyconclusion could remain unchanged even though the fund-flow evidence needed to confirm the buy was missing.Validation
python -m py_compile src/analyzer.pypython -m pytest tests/test_decision_stability.py -q(13 passed)Risk
Reports become more conservative when the configured data source cannot provide fund-flow data. This is intentional for safety, but it may reduce direct buy calls in unsupported/free-data environments.
Rollback
Revert this PR to restore the old skip-calibration behavior for unavailable capital-flow data.