"""模拟盘行情统一接口(raw 真实价 / qfq 前复权,spec §3.3 / §5)。 raw:撮合/涨跌停/成交价用真实价(adjustflag=3 / akshare adjust=""), 从 cfg.data_paths['raw_dir'] 读 parquet(raw 重下脚本生成,单一 adjust 不混源)。 qfq:策略信号用前复权(无除权缺口),从 cfg.data_paths['daily_dir'] 读。 _read_fn 内 lazy import datareader,避免模块级依赖 vnpy 链(tzlocal 等), 本机无 vnpy 完整依赖时仍可 import + 单测(mock _read_fn)。 """ import logging from collections.abc import Iterator logger = logging.getLogger(__name__) def _read_fn(interval: str): """按 interval 返回读取函数(lazy import)。""" if interval == "d": from sanguo_data.datareader import read_parquet_daily return read_parquet_daily if interval == "15m": from sanguo_data.datareader import read_parquet_15min return read_parquet_15min raise ValueError(f"不支持的 interval: {interval}(首版仅 d / 15m)") def _resolve_dir_key(adjust: str, interval: str) -> str: """adjust → cfg.data_paths 的目录 key。 raw 仅支持日线(raw 15min 待分红除权分期项);qfq/默认按 interval 选日线/15min。 """ if adjust == "raw": if interval != "d": raise ValueError( f"raw 模式暂仅支持日线(interval='d'),got '{interval}'" "(raw 15min 待分期项)" ) return "raw_dir" return "daily_dir" if interval == "d" else "minute_15_dir" def _check_raw_cfg(adjust: str, cfg) -> None: """raw 模式需 raw_dir 配置,缺失明确报错(不静默 fallback 到 qfq,避免混源)。""" if adjust == "raw" and (not cfg or "raw_dir" not in getattr(cfg, "data_paths", {})): raise ValueError( "raw 模式需 cfg.data_paths['raw_dir'](未配置;" "先用 scripts/data_platform/raw_redownload.py 生成 raw parquet)" ) def iter_bars( symbols: list[str], start: str, end: str, interval: str, adjust: str = "qfq", cfg=None, ) -> Iterator[tuple]: """按日期 cross-section yield (date, {symbol: BarData})。""" dir_key = _resolve_dir_key(adjust, interval) _check_raw_cfg(adjust, cfg) read_fn = _read_fn(interval) by_date: dict = {} for sym in symbols: for bar in read_fn(sym, start, end, cfg, dir_key): dt = bar.datetime key = dt.date() if hasattr(dt, "date") else dt by_date.setdefault(key, {})[sym] = bar for date in sorted(by_date.keys()): yield date, by_date[date] def fetch_day(symbol: str, date: str, interval: str, adjust: str = "qfq", cfg=None): """实走模式拉当日 bar(C-S3 用)。""" dir_key = _resolve_dir_key(adjust, interval) _check_raw_cfg(adjust, cfg) read_fn = _read_fn(interval) bars = read_fn(symbol, date, date, cfg, dir_key) return bars[-1] if bars else None