fix(HEL-356): complete Shenwan industry signal
Co-authored-by: multica-agent <github@multica.ai>
This commit is contained in:
@@ -169,6 +169,16 @@ class ShenwanIndustryMixin:
|
||||
)
|
||||
else:
|
||||
outer_error = rt_error or outer_error
|
||||
if not outer_precise:
|
||||
# The exact SW L2 member set and every member's final daily bar
|
||||
# are already available. Use their equal-weight move as an
|
||||
# explicitly labelled provisional outer value until Tushare's
|
||||
# official sw_daily row is published.
|
||||
daily = {"change": equal_change}
|
||||
actual_trade_date = trade_date
|
||||
outer_precise = True
|
||||
outer_source = "sw_member_equal_daily"
|
||||
outer_error = ""
|
||||
else:
|
||||
try:
|
||||
snapshot = self._sw_realtime_sector_snapshot(
|
||||
@@ -520,6 +530,12 @@ class ShenwanIndustryMixin:
|
||||
for item in members
|
||||
}
|
||||
equal_change = sum(item["change"] for item in valid) / len(valid) if valid else 0
|
||||
if not outer_precise and inner_precise:
|
||||
official_change = equal_change
|
||||
outer_precise = True
|
||||
outer_source = "sw_member_equal_realtime"
|
||||
outer_error = ""
|
||||
quote_date = trade_date
|
||||
amount_billion = sum(_number(item.get("amount")) for item in valid) / 100000000
|
||||
market_rows: list[dict[str, Any]] = []
|
||||
try:
|
||||
@@ -642,6 +658,11 @@ class ShenwanIndustryMixin:
|
||||
return {}, "", f"申万行业 {sector_code} 盘后正式数据待入库"
|
||||
return {}, "", f"数据中枢申万实时暂不可用:{message[:180]}"
|
||||
if row:
|
||||
actual_name = str(row.get("name") or "").strip()
|
||||
if sector_name and actual_name != str(sector_name).strip():
|
||||
return {}, "", (
|
||||
f"数据中枢返回的行业名称不匹配:期望 {sector_name},实际 {actual_name or '--'}"
|
||||
)
|
||||
return dict(row), str(row.get("source") or "datahub"), ""
|
||||
if finalized:
|
||||
return {}, "", f"申万行业 {sector_code} 当日盘后正式数据尚未入库"
|
||||
|
||||
@@ -802,7 +802,11 @@ def _market_line_scores(
|
||||
{},
|
||||
)
|
||||
sector_quantitative_mode = str(sector.get("_quantitative_mode") or "")
|
||||
actual_sector_source = str(sector.get("source") or "").startswith("tushare_")
|
||||
sector_source = str(sector.get("source") or "")
|
||||
actual_sector_source = (
|
||||
sector_source.startswith("tushare_")
|
||||
or "sw_member_equal_" in sector_source
|
||||
)
|
||||
if (sector.get("realtime") and actual_sector_source) or sector_quantitative_mode == "intraday":
|
||||
sector_change = float(sector.get("change") or 0)
|
||||
sector_change_score = _clamp(sector_change / 5, -1, 1)
|
||||
@@ -831,8 +835,13 @@ def _market_line_scores(
|
||||
f"成分上涨 {int(sector_up)} 家、下跌 {int(sector_down)} 家",
|
||||
f"平均换手 {float(sector.get('turnover_rate') or 0):.2f}%,相对市场 {float(sector.get('relative_turnover') or 0):.2f} 倍",
|
||||
]
|
||||
sector_change_label = (
|
||||
"申万二级行业成分等权涨跌"
|
||||
if "sw_member_equal_" in sector_source
|
||||
else "申万二级行业官方涨跌"
|
||||
)
|
||||
sector_outer_evidence = [
|
||||
f"申万二级行业官方涨跌 {sector_change:+.2f}%",
|
||||
f"{sector_change_label} {sector_change:+.2f}%",
|
||||
f"领涨 {sector.get('leader') or '--'} {float(sector.get('leading_pct') or 0):+.2f}%",
|
||||
]
|
||||
elif actual_sector_source or sector_quantitative_mode == "historical":
|
||||
|
||||
@@ -28,7 +28,7 @@ class HeavenManualMixin:
|
||||
"sector_coverage": {"line": 3, "label": "成分行情覆盖率", "unit": "%", "min": 0, "max": 100},
|
||||
"sector_relative_turnover": {"line": 3, "label": "行业相对市场换手", "unit": "倍", "min": 0, "max": 20},
|
||||
"sector_member_equal_change": {"line": 3, "label": "成分等权涨跌幅", "unit": "%", "min": -100, "max": 100},
|
||||
"sector_change": {"line": 4, "label": "申万官方涨跌幅", "unit": "%", "min": -100, "max": 100},
|
||||
"sector_change": {"line": 4, "label": "申万行业涨跌幅", "unit": "%", "min": -100, "max": 100},
|
||||
"sector_leading_pct": {"line": [3, 4], "label": "行业领涨股涨跌幅", "unit": "%", "min": -100, "max": 100},
|
||||
"market_sentiment_score": {"line": 5, "label": "市场情绪温度", "unit": "分", "min": 0, "max": 100},
|
||||
"market_seal_rate": {"line": 5, "label": "封板率", "unit": "%", "min": 0, "max": 100},
|
||||
|
||||
Reference in New Issue
Block a user