"""akg-factor-bridge CLI。 python run.py views # 连通性自检:打印视图/表行数 python run.py register # 注册四子因子到 factor_metadata python run.py build all --mode history --start 2024-01-01 --end 2025-12-31 python run.py build akg_heat --mode daily --date 2026-07-24 python run.py build akg_event --mode history --start 2025-01-01 --end 2026-07-24 daily 模式:不给 --date 则取今天;start=end=date。history 模式:需 --start/--end。 所有写入幂等(删涉及日期区间再插),可安全重跑。 """ import argparse import datetime as dt import warnings # pandas 用 DBAPI 连接读 SQL 会 warn(无害,功能正常)——静音保持日志干净 warnings.filterwarnings("ignore", message=".*only supports SQLAlchemy.*") import common import db import factors def cmd_views(): checks = [ ("PG v_factor_universe", "pg", "SELECT count(*) FROM v_factor_universe"), ("PG v_factor_consensus", "pg", "SELECT count(*) FROM v_factor_consensus"), ("PG v_factor_events", "pg", "SELECT count(*) FROM v_factor_events"), ("PG v_factor_transmission", "pg", "SELECT count(*) FROM v_factor_transmission"), ("153 stock_fund_heat_scores","heat", "SELECT count(*) FROM stock_fund_heat_scores"), ("平台 gp_day_data", "price", "SELECT count(*) FROM gp_day_data"), ("平台 factor_metadata", "factor", "SELECT count(*) FROM factor_metadata"), ] print("连通性自检:") for name, src, sql in checks: try: df = db.read_pg(sql) if src == "pg" else db.read_mysql(src, sql) print(f" ✅ {name}: {int(df.iloc[0, 0])}") except Exception as e: # noqa: BLE001 print(f" ❌ {name}: {e!r}") fronts = [ ("热度 heat(trade_date)", "heat", "SELECT MAX(trade_date) FROM stock_fund_heat_scores"), ("一致预期 consensus(asof)", "pg", "SELECT MAX(asof_date) FROM v_factor_consensus"), ("事件 events(disclosure)", "pg", "SELECT MAX(disclosure_date) FROM v_factor_events"), ("传导 transmission(scan)", "pg", "SELECT MAX(scan_date) FROM v_factor_transmission"), ("行情 gp_day_data(ts)", "price", "SELECT MAX(`timestamp`) FROM gp_day_data"), ] print("\n数据前沿(各源最新日期——build 的 --date 照此选,别选没数据的未来日):") for name, src, sql in fronts: try: df = db.read_pg(sql) if src == "pg" else db.read_mysql(src, sql) print(f" {name}: {df.iloc[0, 0]}") except Exception as e: # noqa: BLE001 print(f" {name}: ❌ {e!r}") _META = { "akg_upside": ("astock-kg 预期空间", "分析师一致预期目标价隐含收益率(target_mid/price-1)"), "akg_heat": ("astock-kg 热度", "生态日频资金热度分(0~1)"), "akg_event": ("astock-kg 事件", "利好利空事件时间衰减加权分"), "akg_transmission": ("astock-kg 传导", "板块传导未动成员传导强度(路径数×(1-已动比例))"), } def cmd_register(): print("注册四子因子:") for code, (name, desc) in _META.items(): common.register(code, name, factors.FACTORS[code], ["astock-kg", code.split("_", 1)[1]], desc) def cmd_build(which, mode, start, end, date): if mode == "daily": d = date or dt.date.today().isoformat() start = end = d if not start or not end: raise SystemExit("history 模式需要 --start 与 --end") codes = list(factors.FACTORS) if which == "all" else [which] for code in codes: if code not in factors.BUILDERS: raise SystemExit(f"未知因子: {code}(可选: {list(factors.FACTORS)} 或 all)") print(f"[{code}] {mode} {start} ~ {end}") df = factors.BUILDERS[code](start, end) common.write_factor(factors.FACTORS[code], df, mode) def main(): ap = argparse.ArgumentParser(description="akg-factor-bridge") sub = ap.add_subparsers(dest="cmd", required=True) sub.add_parser("views") sub.add_parser("register") b = sub.add_parser("build") b.add_argument("factor", help="akg_upside|akg_heat|akg_event|akg_transmission|all") b.add_argument("--mode", choices=["daily", "history"], default="daily") b.add_argument("--start") b.add_argument("--end") b.add_argument("--date") a = ap.parse_args() if a.cmd == "views": cmd_views() elif a.cmd == "register": cmd_register() elif a.cmd == "build": cmd_build(a.factor, a.mode, a.start, a.end, a.date) if __name__ == "__main__": main()