12 KiB
ashare-data
A股数据抓取工具,股票列表、交易日历使用 AKShare,日线行情使用 BaoStock,其余部分按功能分别使用通达信本地缓存或 AKShare,保存到 MySQL 数据库。
功能概览
| 数据类型 | 说明 | 数据来源 |
|---|---|---|
| 股票列表 | 沪深A股代码、名称、上市日期 | AKShare |
| 交易日历 | 1990年至今的交易日列表 | AKShare |
| 日线行情 | 开高低收、成交量/额、振幅、涨跌幅、换手率(前复权,限沪深 A 股) | BaoStock 日线接口 |
| 新浪1分钟数据 | 最近 1 分钟K线(开高低收、成交量/额) | AKShare 新浪接口 |
| 指数日线 | 上证/沪深300/中证500/中证1000/科创50/深证成指/创业板指/中小板指 | 通达信本地缓存 |
| 涨跌停统计 | 每日主板(10%)/ 科创创业板(20%)涨跌停数量 | stock_daily 汇总 |
| 概念板块 | 通达信本地概念板块缓存 | 通达信本地缓存 |
初始化说明:首次运行 --stock-info / --trading-day 时会自动从 AKShare 拉取并写入数据库;--daily 现在改为 BaoStock 日线接口,只写 stock_daily;--daily-no-data-only 仅更新 stock_no_data;--sector / --index / --intraday 仍按通达信本地缓存工作,不再依赖 hsjday.zip 这类旧的日线初始化包。
快速开始
1. 环境要求
- Python >= 3.10
- MySQL >= 8.0
2. 安装依赖
pip install pymysql sqlalchemy pyyaml pandas requests baostock akshare
说明:当前只需要
pymysql、sqlalchemy、pyyaml、pandas、requests、baostock等基础依赖。 如需使用--sina-min1命令,还需要akshare。 通达信分钟缓存刷新已自动按最多 100 只股票一批拆分。注意通达信客户端原生只支持刷新1m/5m本地缓存。
仅
--sector/--index/--intraday等命令需要通达信本地目录,默认读取config.yaml里的tdx.dir。
3. 配置数据库
⚠️ 安全提示:
config.yaml包含数据库密码,必须保留在.gitignore中(本仓库已默认忽略)。请勿在提交前删除此规则。如曾不慎提交真实密码,参见 TODO.md "清理 git 历史中的明文密码"。
复制配置文件并修改 MySQL 连接信息:
cp config.example.yaml config.yaml
编辑 config.yaml:
mysql:
host: "localhost"
port: 3306
user: "root"
password: "your_password"
database: "ashare"
charset: "utf8mb4"
fetch:
delay: 0.1 # 请求间隔(秒)
retry: 2 # 失败重试次数
workers: 1 # 并发线程数
tdx:
dir: "C:\\new_tdx64" # 通达信安装目录
确保 MySQL 中已创建对应数据库:
CREATE DATABASE ashare CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
4. 运行
# 1. 先抓取股票列表(数据来源: AKShare)
python -m src.main --stock-info
# 2. 抓取交易日历(数据来源: AKShare)
python -m src.main --trading-day --start-date 20100101 --end-date 20261231
# 3. 抓取全历史日线行情(数据来源: BaoStock 日线接口,限沪深 A 股)
python -m src.main --daily --start-date 20260521 --end-date 20260521
# 4. 日常增量更新日线(数据来源: BaoStock 日线接口,限沪深 A 股;只写 stock_daily)
python -m src.main --daily
# 4.1 仅更新停牌/无数据记录,不写 stock_daily(数据来源: BaoStock 日线接口,限沪深 A 股)
python -m src.main --daily-no-data-only --start-date 20100101 --end-date 20260517
# 5. 下载新浪 1 分钟数据并写入 stock_min1(数据来源: AKShare 新浪接口,默认 2010 至今)
python -m src.main --sina-min1
# 6. 下载新浪 1 分钟数据并指定区间(数据来源: AKShare 新浪接口)
python -m src.main --sina-min1 --start-date 20260501 --end-date 20260517 --symbol 600519
# 7. 抓取概念板块及成分股(数据来源: 通达信本地缓存)
python -m src.main --sector
# 8. 汇总每日涨跌停统计(数据来源: stock_daily 汇总)
python -m src.main --market-daily
5. 命令行参数说明
数据抓取选项:
--stock-info 抓取A股股票列表(数据来源: AKShare)
--trading-day 抓取交易日历(数据来源: AKShare)
--daily 抓取日线行情(数据来源: BaoStock 日线接口;限沪深 A 股;增量,自动分析数据缺口,已完整自动跳过;只写入 stock_daily,不更新 stock_no_data)
--daily-no-data-only 仅更新 stock_no_data(数据来源: BaoStock 日线接口;限沪深 A 股;不写入 stock_daily)
--sina-min1 抓取新浪 1 分钟数据并写入 stock_min1(数据来源: AKShare 新浪接口;默认全市场、默认 2010 至今,可配合 --symbol / --start-date / --end-date)
--sector 抓取概念板块及成分股(数据来源: 通达信本地缓存;增量,本地板块已齐全时跳过)
--market-daily 汇总每日涨跌停统计(数据来源: stock_daily 聚合)
--symbol 指定单只或多个股票代码,逗号分隔;不传则抓取全市场,供 --sina-min1 使用
日期过滤(对日线行情、交易日历、新浪1分钟生效;新浪1分钟默认 2010 至今):
--start-date 开始日期,格式 YYYYMMDD
--end-date 结束日期,格式 YYYYMMDD
数据库表结构
stock_info — 股票基本信息
| 字段 | 类型 | 说明 |
|---|---|---|
| code | VARCHAR(10) PK | 股票代码 |
| name | VARCHAR(50) | 股票名称 |
| ipo_date | DATE | 上市日期 |
stock_daily — 日线行情(前复权)
| 字段 | 类型 | 说明 |
|---|---|---|
| code | VARCHAR(10) | 股票代码 |
| date | DATE | 交易日期 |
| open | FLOAT NOT NULL | 开盘价 |
| close | FLOAT NOT NULL | 收盘价 |
| high | FLOAT NOT NULL | 最高价 |
| low | FLOAT NOT NULL | 最低价 |
| volume | FLOAT NOT NULL | 成交量 |
| turnover | FLOAT NOT NULL | 成交额 |
| amplitude | FLOAT NOT NULL | 振幅% |
| pct_change | FLOAT NOT NULL | 涨跌幅% |
| change | FLOAT NOT NULL | 涨跌额 |
| turnover_rate | FLOAT NOT NULL | 换手率% |
联合主键:(code, date)
trading_day — 交易日历(AKShare)
| 字段 | 类型 | 说明 |
|---|---|---|
| date | DATE UQ | 交易日期 |
stock_no_data — 停牌/无数据记录
| 字段 | 类型 | 说明 |
|---|---|---|
| code | VARCHAR(10) | 股票代码 |
| date | DATE | 停牌/无数据日期 |
联合主键:(code, date)
stock_min5 — 分钟K线
| 字段 | 类型 | 说明 |
|---|---|---|
| code | VARCHAR(10) | 股票代码 |
| datetime | DATETIME | 时间 |
| open | FLOAT | 开盘价 |
| high | FLOAT | 最高价 |
| low | FLOAT | 最低价 |
| close | FLOAT | 收盘价 |
| volume | FLOAT | 成交量 |
| amount | FLOAT | 成交额 |
联合主键:(code, datetime)
stock_min1 — 1分钟K线
| 字段 | 类型 | 说明 |
|---|---|---|
| code | VARCHAR(10) | 股票代码 |
| datetime | DATETIME | 时间 |
| open | FLOAT | 开盘价 |
| high | FLOAT | 最高价 |
| low | FLOAT | 最低价 |
| close | FLOAT | 收盘价 |
| volume | FLOAT | 成交量 |
| amount | FLOAT | 成交额 |
联合主键:(code, datetime)
stock_concept — 概念板块及成分股
| 字段 | 类型 | 说明 |
|---|---|---|
| code | VARCHAR(10) | 股票代码 |
| concept_code | VARCHAR(20) | 概念板块代码 |
| concept_name | VARCHAR(100) | 概念板块名称 |
联合主键:(code, concept_code)
index_daily — 指数日线行情
| 字段 | 类型 | 说明 |
|---|---|---|
| code | VARCHAR(10) | 指数代码 |
| date | DATE | 交易日期 |
| open | FLOAT | 开盘价 |
| high | FLOAT | 最高价 |
| low | FLOAT | 最低价 |
| close | FLOAT | 收盘价 |
| volume | FLOAT | 成交量 |
| amount | FLOAT | 成交额 |
| pct_change | FLOAT | 涨跌幅% |
联合主键:(code, date)
market_daily — 每日涨跌停统计
| 字段 | 类型 | 说明 |
|---|---|---|
| date | DATE PK | 交易日期 |
| limit_up_10 | INT | 涨停数(10% 主板) |
| limit_up_20 | INT | 涨停数(20% 科创板/创业板) |
| limit_down_10 | INT | 跌停数(10% 主板) |
| limit_down_20 | INT | 跌停数(20% 科创板/创业板) |
阈值:涨停
pct_change >= 9.8(主板)或>= 19.5(20% 板块);跌停反向。当前可通过python -m src.main --market-daily运行src/fetchers/market_daily.py提供的fetch_market_daily()。
项目结构
ashare-data/
├── config.yaml # MySQL 连接配置(.gitignore)
├── config.example.yaml # 配置文件模板
├── pyproject.toml # 项目元数据
├── requirements.txt # 运行依赖
├── README.md # 项目说明(当前文档)
├── TODO.md # 已知问题与待办事项
├── src/
│ ├── __init__.py
│ ├── config.py # 配置读取模块(YAML + 环境变量 ASHARE_CONFIG)
│ ├── log.py # 统一 logging(控制台 + logs/ashare.log 按日滚动)
│ ├── db.py # SQLAlchemy 模型 + 批量 upsert
│ ├── main.py # 命令行入口
│ └── fetchers/
│ ├── __init__.py
│ ├── stock_list.py # 股票列表(AKShare)
│ ├── trading_day.py # 交易日历(AKShare)
│ ├── daily.py # 日线行情(BaoStock)
│ ├── index.py # 主要指数日线
│ ├── market_daily.py # 每日涨跌停统计(从 stock_daily 聚合)
│ ├── sina_minute.py # 新浪 1 分钟数据(AKShare)
│ └── sector.py # 概念板块及成分股(通达信本地)
├── tests/ # pytest 测试(66 个用例,纯函数 + mock)
├── benchmarks/ # 并发度压测脚本(不在 CI 跑,需真实 MySQL+外网)
└── gzl/ # 选股脚本(独立子项目,可选)
├── Selector.py
└── select_stock.py
设计说明
- 数据源分工:股票列表、交易日历使用 AKShare;日线行情使用 BaoStock;概念板块、指数日线、分钟线等仍按功能读取通达信本地缓存;新浪 1 分钟数据使用 AKShare 新浪接口。
- 线程安全:通达信本地客户端调用集中在
src/fetchers/tdx_client.py。 - 去重写入:所有表通过
db.batch_upsert()走 MySQLINSERT ON DUPLICATE KEY UPDATE,重复执行不会产生重复数据。 - 全量增量:所有模块均支持增量更新——日线按交易日对比找缺口,概念板块在本地已齐全时跳过;新浪 1 分钟数据支持按日期过滤后落库。
- 停牌识别:日线行情若两端已覆盖、内部仍有缺口,则视为停牌,不再重抓。
- 表结构初始化:
init_db()只负责建表。 - 进程内缓存:
get_stock_codes()/get_ipo_dates()缓存全量股票代码与上市日期,避免重复扫库。 - 日志:所有代码通过
from src.log import get_logger输出;控制台 +logs/ashare.log(按日滚动,保留 7 天)双输出,通过ASHARE_LOG_LEVEL=DEBUG切换级别。
运行测试
pip install pytest # 或 pip install -e ".[dev]"
pytest -v
- 当前 66 个用例全部通过,覆盖:
daily._ak_hist_to_rows/daily._fill_derived_fieldsdaily._fetch_one_stockBaoStock 日线读取daily.fetch_dailyBaoStock 日线抓取与落库intraday._tdx_market_data_to_rows/intraday.fetch_intraday通达信分钟抓取market_daily._is_20pct主板/创业板/科创板/北交所判定tdx_blocks.load_infoharbor_blocks通达信本地板块缓存解析sector._fetch_concept_list/sector._fetch_concept_stocks通达信本地概念板块解析sector.fetch_sector概念板块增量跳过逻辑src.log.get_logger命名空间、handler 幂等、env 控制 level
性能压测
python -m benchmarks.bench_daily --codes 200 --days 30 --workers 1,2,4,8
会依次以指定的并发档位跑一遍真实抓取并输出 speedup 表,用于确定 fetch.workers 的最优档位。详见 benchmarks/README.md。
选股子项目 gzl/
gzl/ 目录是独立的选股策略原型(依赖 scipy + 本地 CSV,不读 MySQL)。当前与主项目 src/ 解耦,不参与 python -m src.main 的任何流程。后续是否合并到 src/strategies/ 见 TODO.md。