"""AKShare 数据源(兜底/校验)。免费、无需 token。 默认不安装(依赖较重);如需启用:`uv add akshare`。 fetcher 在 Tushare 失败时会尝试本模块;未安装则该路径自动跳过。 """ from __future__ import annotations from datetime import datetime from ..domain import Bar from .symbols import plain_code def fetch_daily(code: str, start: str = "20200101", end: str | None = None, adjust: str = "qfq") -> list[Bar]: import akshare as ak # 延迟导入 end = end or datetime.now().strftime("%Y%m%d") symbol = plain_code(code) adj_map = {"qfq": "qfq", "hfq": "hfq", "": "", None: ""} df = ak.stock_zh_a_hist( symbol=symbol, period="daily", start_date=start, end_date=end, adjust=adj_map.get(adjust, ""), ) if df is None or df.empty: raise RuntimeError(f"AKShare 无数据: {symbol}") bars: list[Bar] = [] for _, r in df.iterrows(): bars.append( Bar( ts=datetime.strptime(str(r["日期"]), "%Y-%m-%d"), open=float(r["开盘"]), high=float(r["最高"]), low=float(r["最低"]), close=float(r["收盘"]), volume=float(r["成交量"]) * 100.0, # AKShare 成交量单位为手 -> 股 ) ) return bars