Skip to content

Commit d0bb619

Browse files
authored
fix: normalize report strategy price fields (#1264)
1 parent 8a0b093 commit d0bb619

3 files changed

Lines changed: 45 additions & 8 deletions

File tree

api/v1/endpoints/analysis.py

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -797,10 +797,10 @@ def get_analysis_status(task_id: str) -> TaskStatus:
797797
analysis_summary=record.analysis_summary,
798798
),
799799
strategy=ReportStrategy(
800-
ideal_buy=str(getattr(record, 'ideal_buy', None)) if getattr(record, 'ideal_buy', None) is not None else None,
801-
secondary_buy=str(getattr(record, 'secondary_buy', None)) if getattr(record, 'secondary_buy', None) is not None else None,
802-
stop_loss=str(getattr(record, 'stop_loss', None)) if getattr(record, 'stop_loss', None) is not None else None,
803-
take_profit=str(getattr(record, 'take_profit', None)) if getattr(record, 'take_profit', None) is not None else None,
800+
ideal_buy=_stringify_report_strategy_value(getattr(record, 'ideal_buy', None)),
801+
secondary_buy=_stringify_report_strategy_value(getattr(record, 'secondary_buy', None)),
802+
stop_loss=_stringify_report_strategy_value(getattr(record, 'stop_loss', None)),
803+
take_profit=_stringify_report_strategy_value(getattr(record, 'take_profit', None)),
804804
),
805805
).model_dump()
806806
return TaskStatus(
@@ -872,6 +872,14 @@ def _load_sync_fundamental_sources(
872872
return None, None
873873

874874

875+
def _stringify_report_strategy_value(value: Any) -> Optional[str]:
876+
if value is None:
877+
return None
878+
if isinstance(value, str):
879+
return value
880+
return str(value)
881+
882+
875883
def _build_analysis_report(
876884
report_data: Dict[str, Any],
877885
query_id: str,
@@ -932,10 +940,10 @@ def _build_analysis_report(
932940
strategy = None
933941
if strategy_data:
934942
strategy = ReportStrategy(
935-
ideal_buy=strategy_data.get("ideal_buy"),
936-
secondary_buy=strategy_data.get("secondary_buy"),
937-
stop_loss=strategy_data.get("stop_loss"),
938-
take_profit=strategy_data.get("take_profit")
943+
ideal_buy=_stringify_report_strategy_value(strategy_data.get("ideal_buy")),
944+
secondary_buy=_stringify_report_strategy_value(strategy_data.get("secondary_buy")),
945+
stop_loss=_stringify_report_strategy_value(strategy_data.get("stop_loss")),
946+
take_profit=_stringify_report_strategy_value(strategy_data.get("take_profit"))
939947
)
940948

941949
extracted_fundamental = extract_fundamental_detail_fields(

docs/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/).
3232
- [新功能] 通知网关新增默认关闭的进程内降噪配置,支持去重、冷却、静默时段和最低严重级别,并将每日摘要开关标记为预留能力。
3333
- [文档] 恢复多语言 README 新闻源配置表中推荐项的加粗样式,统一相关项目章节层级,并精简顶部导航、联系文案和尾部展示。
3434
- [修复] Docker 挂载的 `logs` 目录不可写时启动日志自动降级到控制台输出,并补充非 root 容器目录权限说明。
35+
- [修复] 修正分析报告 API 构建策略点位时数值字段未归一为字符串的问题,避免策略价格触发响应 DTO 类型校验失败。
3536
- [修复] Docker 启动入口自动修复 `data` / `logs` / `reports` 挂载目录权限并降权运行,文档化的 Compose `exec` 手动命令显式使用 `dsa` 用户,避免普通部署需要手动 `chown` / `chmod`
3637

3738
## [3.16.0] - 2026-05-10

tests/test_analysis_api_contract.py

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -638,6 +638,34 @@ def test_build_analysis_report_extracts_fundamental_fields_from_snapshot(self) -
638638
self.assertEqual(report.details.financial_report["report_date"], "2025-12-31")
639639
self.assertEqual(report.details.dividend_metrics["ttm_dividend_yield_pct"], 2.5)
640640

641+
def test_build_analysis_report_stringifies_strategy_price_fields(self) -> None:
642+
if _build_analysis_report is None:
643+
self.skipTest("analysis endpoint helpers unavailable in this environment")
644+
645+
report = _build_analysis_report(
646+
report_data={
647+
"meta": {},
648+
"summary": {},
649+
"strategy": {
650+
"ideal_buy": 10.0,
651+
"secondary_buy": None,
652+
"stop_loss": 9.5,
653+
"take_profit": 11.6,
654+
},
655+
"details": {},
656+
},
657+
query_id="q1",
658+
stock_code="600519",
659+
stock_name="贵州茅台",
660+
context_snapshot=None,
661+
fallback_fundamental_payload=None,
662+
)
663+
664+
self.assertEqual(report.strategy.ideal_buy, "10.0")
665+
self.assertIsNone(report.strategy.secondary_buy)
666+
self.assertEqual(report.strategy.stop_loss, "9.5")
667+
self.assertEqual(report.strategy.take_profit, "11.6")
668+
641669
def test_build_analysis_report_extracts_related_board_fields_from_snapshot(self) -> None:
642670
if _build_analysis_report is None:
643671
self.skipTest("analysis endpoint helpers unavailable in this environment")

0 commit comments

Comments
 (0)