feat(data): A档第二批接入——新浪资金流×2+同花顺行业/概念榜进ak-events 19:30(用户批方案A);东财push2墙死后免费无墙替代源双机实测秒级零限流(新浪行业资金流90行带净额/领涨股+概念387行,同花顺行业90行×12列+概念375行);快照族语义显式化:端点无date参数无历史回补,19:30采集=收盘终态,节假日拉到上交易日快照接受重复由消费方按交易日历过滤;vintage缺日检查扩全panel族并分档——可回补族(zt_pool×3)近窗洞给回补指引,快照族洞即永久告警查当晚日志无回补指引,旧洞不刷告警防疲劳;+5测试(注册/None/df契约×2+快照族永久洞语义)29绿 [vps]
CI/CD / test (push) Successful in 2s
CI/CD / nas-deploy (push) Successful in 8s
CI/CD / nas-verify (push) Successful in 12s

This commit is contained in:
2026-09-02 08:57:39 +08:00
parent 020d7cda4b
commit 00cfd45d1a
5 changed files with 118 additions and 9 deletions
@@ -133,3 +133,28 @@ class TestZtPoolFamily:
assert status == "empty"
assert (tmp_path / "zt_pool_dtgc" / "20260901_zt_pool_dtgc.parquet").exists()
assert (tmp_path / "zt_pool_dtgc" / ".20260901_zt_pool_dtgc.akshare").exists()
class TestSinaThsFamily:
"""新浪资金流 + 同花顺行业/概念榜 (09-02 用户批 A 档, 东财墙的免费替代)。"""
def test_registered_as_per_date_types(self):
for t in ("fund_flow_industry", "fund_flow_concept",
"ths_industry", "ths_concept"):
assert t in mod.PER_DATE_TYPES
assert t in mod.ALL_TYPES
def test_fetchers_none_on_retry_exhausted(self, monkeypatch):
monkeypatch.setattr(
mod, "call_ak_with_retry", lambda *a, **k: (None, "failed"))
for fetch in (mod.fetch_fund_flow_industry, mod.fetch_fund_flow_concept,
mod.fetch_ths_industry, mod.fetch_ths_concept):
assert fetch("20260902") is None
def test_fetchers_df_on_ok(self, monkeypatch):
df = pd.DataFrame({"净额": [1.0]})
monkeypatch.setattr(mod, "call_ak_with_retry",
lambda *a, **k: (df, "ok"))
for fetch in (mod.fetch_fund_flow_industry, mod.fetch_fund_flow_concept,
mod.fetch_ths_industry, mod.fetch_ths_concept):
assert fetch("20260902") is df
@@ -182,6 +182,24 @@ class TestPanelGapCheck:
assert not any("缺日" in a for a in alerts)
assert status["panel"]["zt_pool"]["n_files"] == 0
def test_snapshot_family_hole_alerts_as_permanent(self, tmp_path):
"""快照族 (无回补能力) 近窗洞 → 告警说『洞即永久/查日志』而非回补指引。"""
_mk_ok_statements(tmp_path)
hole = _recent_weekdays(2)[-1]
dates = _recent_weekdays(6, drop_dates=(hole,))
d = tmp_path / "fund_flow_industry"
d.mkdir(parents=True)
for dt in dates:
(d / f"{dt:%Y%m%d}_fund_flow_industry.parquet").write_bytes(b"x" * 10)
_, alerts = svc.check_all(tmp_path)
assert any("fund_flow_industry" in a and "洞即永久" in a
and hole.isoformat() in a for a in alerts)
# 快照族近窗洞归 holes_permanent (无回补档)
status_panel = svc.panel_gap_check(tmp_path)
assert status_panel["fund_flow_industry"]["holes_backfillable"] == []
assert hole.isoformat() in (
status_panel["fund_flow_industry"]["holes_permanent"])
# ======================== main / JSON 契约 ========================