39 lines
1.3 KiB
Python
39 lines
1.3 KiB
Python
"""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
|