"""连接配置:全部从环境变量/.env 读取,不硬编码任何主机。 三处连接: AKG_PG_* —— astock-kg 基座 PostgreSQL(读四个只读视图,只读账号即可) HEAT_MYSQL_* —— 153 代理 MySQL(读 stock_fund_heat_scores 热度) FACTOR_MYSQL_* —— 平台 PROXY_DB_URL 指向的 MySQL(写 t_factor_* + factor_metadata) 现价来源 PRICE_MYSQL_*(upside 用)默认复用 FACTOR_MYSQL_* 同实例。 """ import os from dataclasses import dataclass try: from dotenv import load_dotenv load_dotenv() except Exception: pass def _req(k: str) -> str: v = os.environ.get(k) if not v: raise RuntimeError(f".env 缺配置: {k}") return v def _opt(k: str, fallback: str) -> str: return os.environ.get(k) or fallback @dataclass(frozen=True) class Conn: host: str port: int user: str password: str db: str def akg_pg() -> Conn: return Conn(_req("AKG_PG_HOST"), int(os.environ.get("AKG_PG_PORT", 5432)), _req("AKG_PG_USER"), os.environ.get("AKG_PG_PASSWORD", ""), _req("AKG_PG_DB")) def heat_mysql() -> Conn: return Conn(_req("HEAT_MYSQL_HOST"), int(os.environ.get("HEAT_MYSQL_PORT", 3306)), _req("HEAT_MYSQL_USER"), os.environ.get("HEAT_MYSQL_PASSWORD", ""), _req("HEAT_MYSQL_DB")) def factor_mysql() -> Conn: return Conn(_req("FACTOR_MYSQL_HOST"), int(os.environ.get("FACTOR_MYSQL_PORT", 3306)), _req("FACTOR_MYSQL_USER"), os.environ.get("FACTOR_MYSQL_PASSWORD", ""), _req("FACTOR_MYSQL_DB")) def price_mysql() -> Conn: """现价(gp_day_data)来源,默认与因子库同实例。""" return Conn(_opt("PRICE_MYSQL_HOST", _req("FACTOR_MYSQL_HOST")), int(_opt("PRICE_MYSQL_PORT", os.environ.get("FACTOR_MYSQL_PORT", "3306"))), _opt("PRICE_MYSQL_USER", _req("FACTOR_MYSQL_USER")), _opt("PRICE_MYSQL_PASSWORD", os.environ.get("FACTOR_MYSQL_PASSWORD", "")), _opt("PRICE_MYSQL_DB", _req("FACTOR_MYSQL_DB"))) # gp_day_data 股票代码列名(待实机核实:ts_code 或 symbol) PRICE_CODE_COL = os.environ.get("PRICE_CODE_COL", "ts_code") FACTOR_API_BASE = os.environ.get("FACTOR_API_BASE", "").rstrip("/")