diff --git a/deploy/profile-scripts/stock_name_hygiene.py b/deploy/profile-scripts/stock_name_hygiene.py new file mode 100644 index 00000000..87d2034f --- /dev/null +++ b/deploy/profile-scripts/stock_name_hygiene.py @@ -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()