1832 字
9 分钟

拿到第一份行情数据:数据源、复权与交易日历

本课目标:从免费数据源拿到第一份 A 股日线数据,理解每个字段的含义、选对复权口径,并把数据规整地存到本地。

常见的免费数据源#

入门阶段不需要花钱买数据,几个常见的 Python 免费数据源足够练手:

数据源特点使用门槛
akshare接口多,覆盖股票、基金、宏观等免费,无需注册
tushare接口规范,文档完整需注册获取 token,部分接口有积分要求
baostock专注股票历史数据,稳定免费,需登录会话

三者的接口风格不同,但返回的核心内容大同小异:一只股票、一段日期、每天一行的开高低收和成交量。建议先选一个用熟,不要来回切换。免费数据源的共同短板是接口偶有变动、数据偶有缺漏,所以拿到数据先检查、再使用,是必须养成的习惯。

还有一个隐蔽问题值得知道:幸存者偏差。有些接口按”当前上市的股票列表”取历史数据,已退市的股票不在其中——用这样的股票池做长期回测,等于事先剔除了所有失败者,结果会系统性偏乐观。入门阶段先在少数标的上练手感受流程,做全市场研究时再认真处理这个问题。

日线数据的字段含义#

一份典型的日线数据长这样:

字段含义备注
date交易日只包含交易日,不含周末节假日
open / high / low / close开、高、低、收注意是什么复权口径
volume成交量单位可能是股或手,务必确认
amount成交额单位可能是元、千元或万元

两个新手常踩的坑:一是单位,不同数据源的成交量单位不统一,“手”(100 股)和”股”差 100 倍;二是复权口径,很多接口默认返回不复权价格,直接拿去算收益率会在除权日出错。

有些接口还会附带涨跌幅、换手率等衍生字段。建议入门阶段只依赖开高低收、成交量这些原始字段,衍生指标自己用代码算——一方面锻炼基本功,另一方面不同数据源的衍生字段口径经常不一致,自己算的才知道口径是什么。

复权口径怎么选#

上一课讲过除权除息,这里给出操作建议:

  • 算收益率、做回测:用后复权。后复权价格从上市第一天起保持可比,跨越任意分红送股都不会出现虚假跳变。前复权有一个隐蔽的问题——每次新的分红发生后,全部历史价格都会被重新调整,导致你上个月存的数据和这个月下载的对不上,回测结果无法复现。
  • 看图、和行情软件对照:用前复权,因为最新价格和实盘一致,看起来直观。
  • 判断涨跌停、估算真实成交价:用不复权。

一个稳妥的做法是同时保存不复权价格和复权因子(或直接保存两套价格),需要哪个口径就用哪个,不要事后互相换算时手忙脚乱。

交易日历与缺失值#

A 股每年大约有 240 多个交易日。周末、法定节假日不交易,个股还可能停牌。这带来两类问题:

  1. 不要用自然日推算。“过去 20 天”在量化语境里几乎总是指 20 个交易日。用 pandas 的日期偏移按自然日取数据,遇到长假会取错。
  2. 区分”市场休市”和”个股停牌”。前者所有股票都没数据,后者只有这只股票没数据。把多只股票对齐到同一个日期索引时,停牌造成的空值需要明确的处理规则——通常价格不前向填充就不要乱填,收益率处理成 0 或空值要想清楚含义。

交易日历本身也可以从数据源获取,拿指数(比如上证指数)的日线日期序列当日历,是一个简单可靠的土办法:

import pandas as pd
# 用指数日线的日期序列充当交易日历
index_df = pd.read_parquet("data/sh000001.parquet")
calendar = pd.DatetimeIndex(index_df["date"]).sort_values()
# 把个股数据对齐到交易日历上,停牌日会显示为 NaN
stock = stock.set_index("date").reindex(calendar)

对齐之后,哪些天停牌一目了然,后续处理停牌的规则也就有了落点。

把数据存下来#

不要每次研究都现场调接口:慢、不稳定、且数据可能悄悄变化导致结果不可复现。建议的流程是”下载一次,本地读取”:

import akshare as ak
# 获取某只股票的后复权日线(示意,接口参数以文档为准)
df = ak.stock_zh_a_hist(
symbol="600519", period="daily",
start_date="20200101", end_date="20251231",
adjust="hfq",
)
df.to_parquet("data/600519_hfq.parquet")

CSV 和 Parquet 的取舍:

  • CSV:肉眼可读,方便用 Excel 检查,但文件大、读取慢、不保存数据类型(日期读回来常变成字符串)。
  • Parquet:列式存储,文件小、读写快、保留类型,适合当作主力格式。

推荐 Parquet 为主、少量 CSV 用于人工抽查。目录按”一个标的一个文件”或”一个市场一张大表”组织都可以,关键是命名里带上复权口径,例如 600519_hfq.parquet,避免几个月后自己都分不清这份数据是什么口径。

另外两条工程习惯值得从第一天就养成。一是增量更新:每天只补最近缺的部分,而不是每次全量重下,既快又减少对免费接口的压力。二是保留下载日期的记录:在文件名或单独的日志里记下这份数据是什么时候下载的,将来发现数据异常时才能回溯。

拿到数据后至少做三项检查:日期是否有重复、价格是否出现零或负值、成交量单位是否与你的预期一致。用 df.describe() 扫一眼各列的最大最小值,用 df.isna().sum() 看看缺失分布,两行代码就能拦下大部分脏数据。数据阶段多花的每一分钟,都会在后面回测排错时成倍地省回来。本文不构成投资建议,数据接口的具体用法以各数据源官方文档为准。

本课小结#

  • akshare、tushare、baostock 都能免费拿到 A 股日线,选一个用熟即可。
  • 拿到数据先确认两件事:成交量单位、复权口径。
  • 回测用后复权,看图用前复权,判断涨跌停用不复权。
  • 时间计算永远以交易日历为准,个股停牌与市场休市要区分对待。
  • 数据下载一次、存成 Parquet 本地复用,文件名里写清复权口径。

动手练习:任选一个数据源,下载一只股票近三年的日线数据,分别以不复权和后复权两种口径各存一份 Parquet。找出两份数据价格差异最大的日期,验证它是否对应一次分红或送股。