feat: stock_name_hygiene 周频任务——akshare官方名剥XD标记比对,stocks/candidates/holdings截断名与ST变更自愈

This commit is contained in:
xxm
2026-08-22 12:22:09 +08:00
parent 0afff445b6
commit 761706ca8f
@@ -0,0 +1,65 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""stock_name_hygiene.py — 股票名称卫生(每周)
2026-08-22 名称治理:XD/XR/DR 除权息日交易所简称被截断(紫金矿业→XD紫金矿),
各行情源当天均无干净名。本任务每周拉 akshare 官方全量名称,剥 XD 标记后比对,
凡 DB 名是官方名的前缀(截断)即以官方名为准修复,自愈截断/改名/ST 变更。
"""
import os, sys, re
from datetime import datetime
# ── 消息通道统一路由(broadcast/xmpp by delivery) ──
try:
from messenger import install_stdio_hook as _msh
_msh()
except Exception:
pass
DB_PATH = os.environ.get("MOFIN_DB", "/home/hmo/MoFin/data/mofin.db")
def strip_marker(n: str) -> str:
m = re.match(r"^(XD|XR|DR)(.+)$", n)
return m.group(2) if m else n
def main():
import sqlite3
import akshare as ak
print(f"[stock_name_hygiene] {datetime.now():%Y-%m-%d %H:%M:%S} 开始", flush=True)
df = ak.stock_info_a_code_name()
name_map = {str(c): strip_marker(str(n)) for c, n in zip(df["code"], df["name"])}
print(f" 官方名称源: {len(name_map)}", flush=True)
conn = sqlite3.connect(DB_PATH, timeout=30)
conn.row_factory = sqlite3.Row
total = 0
samples = []
for table in ["stocks", "candidates", "holdings"]:
try:
rows = conn.execute(f"SELECT code, name FROM {table}").fetchall()
except Exception:
continue
fixed = 0
for r in rows:
code, cur = str(r["code"]), str(r["name"])
full = name_map.get(code)
if not full or full == cur:
continue
# 只修明确劣化:DB名是官方名前缀(XD截断)、或DB名=代码、或仅ST标记差异
if full.startswith(cur) or cur == code or cur.lstrip("*ST") == full.lstrip("*ST"):
conn.execute(f"UPDATE {table} SET name=? WHERE code=? AND name=?", (full, code, cur))
fixed += 1
if len(samples) < 8:
samples.append(f"{code} {cur}{full}")
if fixed:
print(f" {table}: 修复 {fixed}", flush=True)
total += fixed
conn.commit()
conn.close()
print(f"[stock_name_hygiene] 完成,共修复 {total}" + (f"(样本: {'; '.join(samples)}" if samples else ""), flush=True)
if __name__ == "__main__":
main()