mirror of
https://ghfast.top/https://github.com/aeroxw/tick-stock-panel.git
synced 2026-09-12 16:44:15 +08:00
fix(rotation): AI 轮动分析的大盘背景不再把指数涨跌幅放大 100 倍
「概念分析/行业分析 → AI 轮动分析」生成的报告里, 大盘部分写成「上证指数 上涨 123%」「深证成指下跌 45%」, 第 5 节「结合大盘」的结论也跟着跑偏。 _build_market_block 用 _fmt_pct 渲染指数涨跌幅, 而 _fmt_pct 是给概念/行业 涨幅(小数口径)写的, 会 *100。但 overview["indices"][].change_pct 是百分数 口径 (CONTRIBUTING §3.1): quote_service._build_index_quotes 的注释写明 "统一转成百分比输出", DB 兜底的 _index_quotes 同样 change_amount/pc*100。 于是 1.23 被渲染成 +123.00% 送进提示词。 新增 _fmt_index_pct 按百分数口径直接格式化, 与 market_recap._build_indices_block (同一份 overview, 不 *100) 和 abnormal_moves._bench_rt_pct (消费前显式 /100) 的口径对齐; 概念/行业涨幅仍走原来的 _fmt_pct。
This commit is contained in:
@@ -206,11 +206,24 @@ def _compute_rotation_signals(dates: list[str], columns: dict) -> dict:
|
||||
# ================================================================
|
||||
|
||||
def _fmt_pct(v) -> str:
|
||||
"""概念/行业涨幅: 小数口径 (0.0522 = +5.22%), 展示前乘 100。"""
|
||||
if v is None:
|
||||
return "—"
|
||||
return f"{v*100:+.2f}%"
|
||||
|
||||
|
||||
def _fmt_index_pct(v) -> str:
|
||||
"""指数涨跌幅: 百分数口径 (CONTRIBUTING §3.1), 直接展示, 不能再乘一次 100。
|
||||
|
||||
build_market_overview 的 indices[].change_pct 在数据边界已转成百分数
|
||||
(quote_service._build_index_quotes 与 _index_quotes 的 DB 兜底都已乘过 100),
|
||||
与 market_recap._build_indices_block 的展示口径一致。
|
||||
"""
|
||||
if v is None:
|
||||
return "—"
|
||||
return f"{v:+.2f}%"
|
||||
|
||||
|
||||
def _build_market_block(overview: dict) -> str:
|
||||
"""大盘背景精简块 (复用 market_overview 已算好的字段)。"""
|
||||
indices = overview.get("indices") or []
|
||||
@@ -222,7 +235,7 @@ def _build_market_block(overview: dict) -> str:
|
||||
for idx in indices[:4]:
|
||||
name = idx.get("name") or idx.get("symbol") or "?"
|
||||
chg = idx.get("change_pct")
|
||||
idx_lines.append(f"{name} {_fmt_pct(chg)}")
|
||||
idx_lines.append(f"{name} {_fmt_index_pct(chg)}")
|
||||
idx_str = " / ".join(idx_lines) or "指数缺失"
|
||||
|
||||
total_amount = (amt.get("total") or 0) / 1e8 # 元 → 亿
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
"""AI 轮动分析提示词里的「大盘背景」指数涨跌幅必须按百分数口径。
|
||||
|
||||
CONTRIBUTING §3.1: build_market_overview 的 indices[].change_pct 是百分数
|
||||
(quote_service._build_index_quotes 在数据边界已乘过 100, DB 兜底路径同样乘过 100)。
|
||||
概念/行业涨幅则是小数。两者共用一个 _fmt_pct 会把指数再放大 100 倍,
|
||||
喂给 LLM 的大盘背景变成「上证指数 +123.00%」。
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
from app.services.concept_rotation_analyzer import (
|
||||
_build_market_block,
|
||||
_build_signal_block,
|
||||
)
|
||||
|
||||
|
||||
def _overview() -> dict:
|
||||
"""与 build_market_overview 返回结构一致的最小切片。"""
|
||||
return {
|
||||
"indices": [
|
||||
{"symbol": "000001.SH", "name": "上证指数", "change_pct": 1.23},
|
||||
{"symbol": "399001.SZ", "name": "深证成指", "change_pct": -0.45},
|
||||
],
|
||||
"emotion": {"score": 62, "label": "偏暖"},
|
||||
"limit": {"limit_up": 68, "broken": 20, "limit_down": 3, "max_boards": 5},
|
||||
"amount": {"total": 1.2e12},
|
||||
}
|
||||
|
||||
|
||||
def test_index_change_pct_is_not_scaled_again():
|
||||
block = _build_market_block(_overview())
|
||||
|
||||
assert "上证指数 +1.23%" in block
|
||||
assert "深证成指 -0.45%" in block
|
||||
assert "123.00%" not in block
|
||||
|
||||
|
||||
def test_missing_index_change_pct_renders_placeholder():
|
||||
overview = _overview()
|
||||
overview["indices"][0]["change_pct"] = None
|
||||
|
||||
assert "上证指数 —" in _build_market_block(overview)
|
||||
|
||||
|
||||
def test_dimension_pct_is_still_scaled_from_decimal():
|
||||
"""概念/行业涨幅仍是小数口径, 必须乘 100 后展示 (不能被一起改掉)。"""
|
||||
items = [{
|
||||
"concept": "人工智能",
|
||||
"ranks": [3, 1],
|
||||
"pcts": [0.05, 0.07],
|
||||
"avg_rank": 2.0,
|
||||
"rank_std": 1.0,
|
||||
}]
|
||||
|
||||
block = _build_signal_block("主线", items)
|
||||
|
||||
assert "区间均涨 +6.00%" in block
|
||||
Reference in New Issue
Block a user