AlphaKit 数据研究工作台

Python 获取 A 股历史日线:先检查,再排序

用 AlphaKit SDK 查询明确历史区间,在 pandas 中检查空数据、字段、日期、重复行与数值,并区分原始收盘价和复权收益。

研究实践 · 更新于

本页内容

这次要解决什么问题?

获取数据只是第一步。这篇教程将单只股票的历史日线整理成一张日期正确、每个交易日只有一行、按时间排列的表,再导出 CSV。

案例固定为 2026 年 6 月 1 日至 6 月 30 日,使用 600519.SH 演示参数写法。代码只是方法示例,历史数据不代表当前行情,也不用于挑选股票或判断交易方向。

查询之前

先按 SDK 入门安装并初始化 api。真实查询需要有效 Token 与管理方确认的 HTTPS 网关。

下面的代码只使用当前客户端已有的 daily() 方法。不要用隐含的“最近一年”替代教程的固定日期,也不要先请求全市场再从结果中筛选一只股票。

raw = api.daily(
    ts_code="600519.SH",
    start_date="20260601",
    end_date="20260630",
)

把返回结果变成可核对的表

接上前面的查询代码:

from pathlib import Path
import numpy as np
import pandas as pd

if raw.empty:
    raise ValueError("没有返回日线,请核对参数、权限和数据覆盖")

required = {"ts_code", "trade_date", "close"}
missing = required - set(raw.columns)
if missing:
    raise ValueError(f"缺少必要字段:{sorted(missing)}")

df = raw.copy()
df["ts_code"] = df["ts_code"].astype("string").str.strip()
date_text = df["trade_date"].astype("string").str.strip()
if not date_text.str.fullmatch(r"[0-9]{8}").fillna(False).all():
    raise ValueError("交易日期应为八位 YYYYMMDD")
df["trade_date"] = pd.to_datetime(
    date_text,
    format="%Y%m%d", errors="raise",
)
if df["ts_code"].isna().any() or df["trade_date"].isna().any():
    raise ValueError("标的或交易日期有缺失")
if not df["ts_code"].eq("600519.SH").all():
    raise ValueError("返回了请求标的以外的数据")
if not df["trade_date"].between("2026-06-01", "2026-06-30").all():
    raise ValueError("返回日期超出请求区间")
if df.duplicated(["ts_code", "trade_date"]).any():
    raise ValueError("同一标的同一天有重复行,先核对来源")

df["close"] = pd.to_numeric(df["close"], errors="raise")
if df["close"].isna().any() or not np.isfinite(df["close"]).all():
    raise ValueError("收盘价存在缺失或非有限数值")
if not df["close"].gt(0).all():
    raise ValueError("收盘价存在非正数,先核对数据")

df = df.sort_values(["ts_code", "trade_date"]).reset_index(drop=True)
print(df[["ts_code", "trade_date", "close"]].to_string(index=False))

output = Path("daily_history.csv")
df.to_csv(output, index=False, encoding="utf-8-sig", date_format="%Y-%m-%d")
print("已保存:", output.resolve())

这些检查遇到异常会停止。重复日期不能悄悄删除;缺失价格也不能直接填成零。先核对异常,才能决定是否继续分析。

代码中的 numpy 随 pandas 的依赖安装。CSV 保存在运行时的当前目录;运行前确认目录,避免覆盖同名文件。

输出应该怎样看?

核对项 怎样阅读
标的 每行都是请求的股票代码
日期 位于请求区间内,按先后排序,单个标的没有重复日期
行数 是接口实际返回的行数,不等于自然日天数
收盘价 保留接口返回的价格,用于后续口径检查
其他字段 在使用前核对名称、单位、是否缺失和数据来源说明

仅有返回的日线,不能证明请求区间内所有预期交易日都完整。要检查覆盖率,还需要交易日历、停复牌资料及账户数据范围。不要用自然日补出周末或节假日的“交易行”。

没有 Token:用合成样本练习

可以下载完整示例。解压后进入含 daily_history.py 的目录,运行:

python -m pip install -r requirements.txt
python daily_history.py --demo

演示模式使用合成样本,不访问接口、不需要 Token。合成日期和价格只用于检查程序流程,不是实际行情或预期真实输出;真实查询时的行数和数值以接口结果为准。

完整脚本在项目中的位置是 examples/sdk/daily_history.py。默认只打印结果,加入 --csv 后将输出保存到当前目录下的 outputs/sdk-examples/,也可通过 --output-dir 指定其他目录。重复运行会覆盖同名输出,需要保留时请换一个目录。

获得配置后,真实模式用明确参数运行:

python daily_history.py --ts-code 600519.SH --start-date 20260601 --end-date 20260630 --csv

本页核心片段也可以独立复制;完整脚本的参数说明见 python daily_history.py --help。

为什么这里不直接计算投资收益?

daily() 返回的原始价格不是已经处理完分红、拆分等变化的复权收益序列。两天收盘价相除得到的价格变化,不一定等于可比较的持有收益。

若研究长期表现,应先确认价格口径、复权因子、交易日和所需成本。这个教程先把输入整理清楚,不把原始价格变化当成完整策略成绩。

下一步可以把这张表与每日估值数据按日期对齐:Python 合并行情与 PE/PB。