fix(HEL-356): complete Shenwan industry signal
Co-authored-by: multica-agent <github@multica.ai>
This commit is contained in:
@@ -197,17 +197,22 @@ def fetch_sector_quote(db: HubDB, code: str, expected_date: str = "") -> dict[st
|
||||
if ts_code.isdigit():
|
||||
ts_code = f"{ts_code}.SI"
|
||||
cache_key = f"sector:{ts_code}"
|
||||
canonical_name = _canonical_sw_name(db, ts_code)
|
||||
cached = _read_cache(db, cache_key)
|
||||
if cached is not None:
|
||||
if cached is not None and _sector_payload_matches(cached, canonical_name):
|
||||
return cached
|
||||
errors: list[str] = []
|
||||
try:
|
||||
row = EastmoneyAdapter().fetch_shenwan_quote(ts_code)
|
||||
if not _sector_row_matches(row, canonical_name):
|
||||
raise AdapterError(
|
||||
f"industry name mismatch: expected {canonical_name}, got {row.get('name') or '--'}"
|
||||
)
|
||||
source = str(row.get("source") or "eastmoney_sw")
|
||||
except Exception as exc:
|
||||
errors.append(f"eastmoney:{exc}")
|
||||
recovered = _load_quotes_lkg(db, cache_key, expected_date)
|
||||
if recovered is not None:
|
||||
if recovered is not None and _sector_payload_matches(recovered, canonical_name):
|
||||
return recovered
|
||||
raise RealtimeApiError(
|
||||
"SOURCE_UNAVAILABLE",
|
||||
@@ -217,7 +222,7 @@ def fetch_sector_quote(db: HubDB, code: str, expected_date: str = "") -> dict[st
|
||||
quote_date = str(row.get("quote_date") or "")
|
||||
if want and quote_date and quote_date != want:
|
||||
recovered = _load_quotes_lkg(db, cache_key, want)
|
||||
if recovered is not None:
|
||||
if recovered is not None and _sector_payload_matches(recovered, canonical_name):
|
||||
return recovered
|
||||
raise RealtimeApiError("SOURCE_UNAVAILABLE", f"sector quote date {quote_date} != {want}")
|
||||
payload = _envelope(
|
||||
@@ -235,6 +240,29 @@ def fetch_sector_quote(db: HubDB, code: str, expected_date: str = "") -> dict[st
|
||||
return payload
|
||||
|
||||
|
||||
def _canonical_sw_name(db: HubDB, ts_code: str) -> str:
|
||||
row = db.fetchone(
|
||||
"SELECT name FROM sector_master WHERE ts_code = ? AND family = 'sw'",
|
||||
(ts_code,),
|
||||
)
|
||||
if not row:
|
||||
row = db.fetchone(
|
||||
"SELECT name FROM eod_sector_daily WHERE ts_code = ? AND family = 'sw' "
|
||||
"ORDER BY trade_date DESC LIMIT 1",
|
||||
(ts_code,),
|
||||
)
|
||||
return str((row or {}).get("name") or "").strip()
|
||||
|
||||
|
||||
def _sector_row_matches(row: dict[str, Any], canonical_name: str) -> bool:
|
||||
return not canonical_name or str(row.get("name") or "").strip() == canonical_name
|
||||
|
||||
|
||||
def _sector_payload_matches(payload: dict[str, Any], canonical_name: str) -> bool:
|
||||
data = payload.get("data") if isinstance(payload, dict) else None
|
||||
return isinstance(data, dict) and _sector_row_matches(data, canonical_name)
|
||||
|
||||
|
||||
def fetch_limit_pool(db: HubDB, trade_date: str = "") -> dict[str, Any]:
|
||||
day = yyyymmdd(trade_date or now_shanghai())
|
||||
cache_key = f"limit-pool:{day}"
|
||||
@@ -489,18 +517,29 @@ def warm_realtime(db: HubDB) -> dict[str, Any]:
|
||||
try:
|
||||
masters = db.fetchall(
|
||||
"""
|
||||
SELECT ts_code FROM sector_master WHERE family = 'sw'
|
||||
UNION
|
||||
SELECT ts_code FROM eod_sector_daily WHERE family = 'sw'
|
||||
ORDER BY ts_code
|
||||
SELECT ts_code, name, 0 AS priority FROM sector_master WHERE family = 'sw'
|
||||
UNION ALL
|
||||
SELECT ts_code, name, 1 AS priority FROM eod_sector_daily WHERE family = 'sw'
|
||||
ORDER BY priority, ts_code
|
||||
"""
|
||||
)
|
||||
codes = [str(row.get("ts_code") or "") for row in masters if row.get("ts_code")]
|
||||
sector_rows = _eastmoney_sector_quotes(codes)
|
||||
for row in sector_rows:
|
||||
canonical_names: dict[str, str] = {}
|
||||
for master in masters:
|
||||
master_code = str(master.get("ts_code") or "")
|
||||
master_name = str(master.get("name") or "").strip()
|
||||
if master_code and master_name:
|
||||
canonical_names.setdefault(master_code, master_name)
|
||||
codes = list(canonical_names)
|
||||
fetched_sector_rows = _eastmoney_sector_quotes(codes)
|
||||
for row in fetched_sector_rows:
|
||||
if _row_quote_date(row, today) != today:
|
||||
continue
|
||||
code = str(row.get("ts_code") or "").upper()
|
||||
if not _sector_row_matches(row, canonical_names.get(code, "")):
|
||||
result["errors"].append(
|
||||
f"sector:{code}:industry name mismatch"
|
||||
)
|
||||
continue
|
||||
payload = _envelope(
|
||||
row,
|
||||
{
|
||||
@@ -513,6 +552,7 @@ def warm_realtime(db: HubDB) -> dict[str, Any]:
|
||||
},
|
||||
)
|
||||
_write_cache(db, f"sector:{code}", payload, INDEX_TTL, "eastmoney_sw")
|
||||
sector_rows.append(row)
|
||||
result["sectors"] = len(sector_rows)
|
||||
result["rows"] += len(sector_rows)
|
||||
except Exception as exc:
|
||||
|
||||
Reference in New Issue
Block a user