SHA256
307 lines
12 KiB
Markdown
307 lines
12 KiB
Markdown
# 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. 安装依赖
|
||
|
||
```bash
|
||
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](./TODO.md) "清理 git 历史中的明文密码"。
|
||
|
||
复制配置文件并修改 MySQL 连接信息:
|
||
|
||
```bash
|
||
cp config.example.yaml config.yaml
|
||
```
|
||
|
||
编辑 `config.yaml`:
|
||
|
||
```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 中已创建对应数据库:
|
||
|
||
```sql
|
||
CREATE DATABASE ashare CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||
```
|
||
|
||
### 4. 运行
|
||
|
||
```bash
|
||
# 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()` 走 MySQL `INSERT 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` 切换级别。
|
||
|
||
## 运行测试
|
||
|
||
```bash
|
||
pip install pytest # 或 pip install -e ".[dev]"
|
||
pytest -v
|
||
```
|
||
|
||
- 当前 66 个用例全部通过,覆盖:
|
||
- `daily._ak_hist_to_rows` / `daily._fill_derived_fields`
|
||
- `daily._fetch_one_stock` BaoStock 日线读取
|
||
- `daily.fetch_daily` BaoStock 日线抓取与落库
|
||
- `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
|
||
|
||
## 性能压测
|
||
|
||
```bash
|
||
python -m benchmarks.bench_daily --codes 200 --days 30 --workers 1,2,4,8
|
||
```
|
||
|
||
会依次以指定的并发档位跑一遍真实抓取并输出 speedup 表,用于确定 `fetch.workers` 的最优档位。详见 [benchmarks/README.md](./benchmarks/README.md)。
|
||
|
||
## 选股子项目 `gzl/`
|
||
|
||
`gzl/` 目录是独立的选股策略原型(依赖 `scipy` + 本地 CSV,不读 MySQL)。当前与主项目 `src/` 解耦,**不参与** `python -m src.main` 的任何流程。后续是否合并到 `src/strategies/` 见 [TODO.md](./TODO.md)。
|