行业催化只进提议卡与账本,不送研判;单测(台账 051)
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
parent
7dcf039cf3
commit
499b1342e4
|
|
@ -695,6 +695,8 @@ def eval_open(c: dict, params: dict, caps: dict, room_amt: float):
|
|||
"pricing_state": c.get("pricing_state"), "pricing_text": c.get("pricing_text"),
|
||||
# 相关快讯 (2026-09-08 台账 050): 原值进账本与提议卡, 整句另送研判。只是上下文, 不进判定。
|
||||
"news": c.get("news"), "news_text": c.get("news_text"),
|
||||
# 行业催化 (2026-09-08 台账 051): 环节级, 原值进账本与提议卡; 产业逻辑不送研判。
|
||||
"industry_catalyst": c.get("industry_catalyst"), "industry_catalyst_text": c.get("industry_catalyst_text"),
|
||||
# ---- 仓位口径: 只进评审账本做判分锚。judge.py 送研判时会把这几项过滤掉,
|
||||
# 理由见那边的 OPEN_JUDGE_KEYS —— 决策系统本来就不管仓位, 别送过去带偏它。
|
||||
"target_pct": target_pct, "target_amount": round(full_amt, 2),
|
||||
|
|
|
|||
|
|
@ -189,6 +189,22 @@ def _news_or_none(v, limit=5):
|
|||
return {"count": count, "latest": _text_or_none(v.get("latest")), "items": items}
|
||||
|
||||
|
||||
def _industry_catalyst_or_none(v, limit=3):
|
||||
"""行业催化 (2026-09-08 台账 051): 上游按环节标出的行业级催化, 只留最多 limit 条固定键。
|
||||
产业逻辑不送研判 (judge.OPEN_JUDGE_KEYS 不收), 只进硬数字给人看与复盘。"""
|
||||
if not isinstance(v, list) or not v:
|
||||
return None
|
||||
out = []
|
||||
for it in v:
|
||||
if not isinstance(it, dict) or not it.get("title"):
|
||||
continue
|
||||
out.append({k: _text_or_none(it.get(k)) for k in
|
||||
("segment", "event_date", "title", "direction", "magnitude", "horizon", "confidence", "mechanism")})
|
||||
if len(out) >= limit:
|
||||
break
|
||||
return out or None
|
||||
|
||||
|
||||
def _events_or_none(v):
|
||||
"""催化事件归一 (2026-09-08): 上游给 {latest, count, events:[{date, types, orgs, title, n_reports, compound}]}。
|
||||
只收约定的键, 事件最多五条; 不是字典或没有事件一律 None。"""
|
||||
|
|
@ -290,6 +306,9 @@ def _rows(raw, bucket: str) -> list:
|
|||
# (judge.OPEN_JUDGE_KEYS 收 news_text)。只是上下文, 不判正负, 不进任何判定。
|
||||
"news": _news_or_none(it.get("news")),
|
||||
"news_text": _text_or_none(it.get("news_text")),
|
||||
# 行业催化 (2026-09-08 台账 051): 环节级, 只给人看与复盘, 不送研判、不进判定。
|
||||
"industry_catalyst": _industry_catalyst_or_none(it.get("industry_catalyst")),
|
||||
"industry_catalyst_text": _text_or_none(it.get("industry_catalyst_text")),
|
||||
})
|
||||
return out
|
||||
|
||||
|
|
@ -485,7 +504,9 @@ def select_candidates(plan: dict, *, held=(), black=(), top_n: int = 30, tiers=N
|
|||
"valuation_text": r.get("valuation_text"),
|
||||
"events": r.get("events"), "events_text": r.get("events_text"),
|
||||
"pricing_state": r.get("pricing_state"), "pricing_text": r.get("pricing_text"),
|
||||
"news": r.get("news"), "news_text": r.get("news_text")}
|
||||
"news": r.get("news"), "news_text": r.get("news_text"),
|
||||
"industry_catalyst": r.get("industry_catalyst"),
|
||||
"industry_catalyst_text": r.get("industry_catalyst_text")}
|
||||
for r in passed[:n]]
|
||||
return {"date": plan.get("date"), "considered": len(pool), "eligible": len(passed),
|
||||
"items": items, "dropped": dropped, "st_unknown": st_unknown,
|
||||
|
|
|
|||
|
|
@ -1035,6 +1035,7 @@ body.dock-r:not(.r-fold) .side-r .strip{display:none;}
|
|||
<div class="st muted" v-if="propText(p, 'events_text')">{{ propText(p, 'events_text') }}</div>
|
||||
<div class="st muted" v-if="propText(p, 'pricing_text')">{{ propText(p, 'pricing_text') }}</div>
|
||||
<div class="st muted" v-if="propText(p, 'news_text')">{{ propText(p, 'news_text') }}</div>
|
||||
<div class="st muted" v-if="propText(p, 'industry_catalyst_text')">{{ propText(p, 'industry_catalyst_text') }}</div>
|
||||
<div class="st" v-if="propHeads(p)"><span class="muted">择时层两个期限:</span>{{ propHeads(p) }}</div>
|
||||
<div class="st muted">{{ propWhy(p) }}</div>
|
||||
<div class="st">约 {{ p.qty }} 股 · 参考价 {{ (p.hard_numbers||{}).price==null ? '—' : (p.hard_numbers||{}).price }}
|
||||
|
|
|
|||
|
|
@ -499,6 +499,32 @@ def test_news_passthrough():
|
|||
assert "news_text" in jd.OPEN_JUDGE_KEYS
|
||||
|
||||
|
||||
@case("行业催化: 裁到三条固定键进硬数字与提议卡, 不送研判 (台账 051)")
|
||||
def test_industry_catalyst_passthrough():
|
||||
lst = [{"segment": f"环节{i}", "event_date": "2026-09-05", "title": f"催化{i}", "direction": "利好",
|
||||
"magnitude": "大", "horizon": "长期", "confidence": "中", "mechanism": "m", "extra": 1} for i in range(4)]
|
||||
row = pf._rows([{"code": "600000.SH", "rank": 1, "score": 210, "industry_catalyst": lst,
|
||||
"industry_catalyst_text": "行业催化(环节级,数据基座按材料标出,4 条,不进判决):…"}], "main")[0]
|
||||
assert len(row["industry_catalyst"]) == 3 and "extra" not in row["industry_catalyst"][0]
|
||||
assert row["industry_catalyst_text"].startswith("行业催化")
|
||||
empty = pf._rows([{"code": "600000.SH", "rank": 1, "score": 210, "industry_catalyst": [], "industry_catalyst_text": None}], "main")[0]
|
||||
assert empty["industry_catalyst"] is None and empty["industry_catalyst_text"] is None
|
||||
plan = {"date": "2026-09-08", "main": [row], "observe": []}
|
||||
item = pf.select_candidates(plan, top_n=10)["items"][0]
|
||||
assert item["industry_catalyst"][0]["segment"] == "环节0", item
|
||||
c = {**item, "price": 10.0}
|
||||
params = {"scale": 1_000_000, "stock_target_default": 0.06, "batch_split": (0.5, 0.25, 0.25)}
|
||||
with _Patch() as p:
|
||||
p(ae, "check_all_caps", lambda **kw: [])
|
||||
p(ae, "_new_name_ctx", lambda caps, c: caps)
|
||||
cand, why = ae.eval_open(c, params, {"names_count": 0, "max_names": 10}, 500_000)
|
||||
hn = cand["hard_numbers"]
|
||||
assert hn["industry_catalyst_text"] == row["industry_catalyst_text"], why
|
||||
sent = jd._judge_hard_numbers("OPEN", hn)
|
||||
assert "industry_catalyst" not in sent and "industry_catalyst_text" not in sent, sent
|
||||
assert "industry_catalyst_text" not in jd.OPEN_JUDGE_KEYS
|
||||
|
||||
|
||||
@case("参考目标价·状态应答里的估值子字典归一, 持仓行只在算得出时给 ref_target, 算不出或缺就不给")
|
||||
def _():
|
||||
val = {"neut": 56.05, "pess": 42.64, "opt": 84.96, "price": 50.17, "quarter": "2026Q4", "firms": 8,
|
||||
|
|
|
|||
Loading…
Reference in New Issue