7 Sprints 全部完成: Sprint 0: 基础设施 (DataManager + MariaDB) Sprint 1: 因子引擎 (34因子/12分类) Sprint 2: VectorBT 回测 (5策略+截面) Sprint 3: Optuna 优化 (+Walk-Forward) Sprint 4: ML 模型 (LightGBM+CatBoost) Sprint 5: Qwen 情绪因子 (三源新闻+日期对齐) Sprint 6: Agent 系统 (4Agent+日报.md/.html) 生产加固 (15项): Tushare双源fallback, SSH自动恢复, pool_pre_ping, save_daily先删后插, load_dotenv绝对路径, 日报5d/20d修复, RiskAgent改上证指数, 昨日对比+数据截止, mac_report utf8mb4, CLAUDE-*.md 9条已知Bug, demo全参数化, djapi数据源归一化, indexDatas API修正 Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
100 lines
3.7 KiB
Markdown
100 lines
3.7 KiB
Markdown
# CLAUDE-data.md — 数据层 + 数据库
|
||
|
||
## DataManager (`finance/data/data_manager.py`)
|
||
|
||
双数据源:Tushare(优先)→ AkShare(fallback)。DB 缓存优先。
|
||
|
||
```python
|
||
from data.data_manager import DataManager
|
||
dm = DataManager()
|
||
dm.init_db() # 首次建表(幂等)
|
||
```
|
||
|
||
### 关键方法
|
||
|
||
```python
|
||
stocks = dm.get_stock_list() # → 5524 只, DB 优先
|
||
daily = dm.get_daily("000001.SZ") # DB优先 → Tushare → AkShare
|
||
fina = dm.get_financial("000001.SZ") # 同花顺 + fallback
|
||
n = dm.sync_daily("000001.SZ") # 增量同步: latest>=today → 跳过
|
||
```
|
||
|
||
### 指数 vs 个股路由
|
||
|
||
`_try_fetch()` 自动检测 `is_index_code()`:
|
||
- `000001.SH` / `399001.SZ` → `fetch_index_daily()`(Tushare `index_daily` / AkShare `index_zh_a_hist`)
|
||
- `000001.SZ` / `600519.SH` → `fetch_daily()`(stock daily)
|
||
|
||
### 数据源 (`finance/data/sources/`)
|
||
|
||
- `akshare_source.py` — `AkShareSource`(个股+指数+财务)
|
||
- `tushare_source.py` — `TushareSource`(需 `TUSHARE_TOKEN`,`available=False` 自动跳过)
|
||
|
||
## 数据库 (`finance/database/`)
|
||
|
||
### 连接
|
||
|
||
```python
|
||
from database.connection import get_engine, test_connection
|
||
# get_engine() 自动检测断连 → 运行 autossh.sh → 重建引擎
|
||
```
|
||
|
||
### 表结构(mac_ 前缀)
|
||
|
||
| 表 | 内容 | 主键 |
|
||
|----|------|------|
|
||
| `mac_stock_basic` | A股列表, 5524只 | ts_code |
|
||
| `mac_stock_daily` | 日线 OHLCV | (ts_code, trade_date) |
|
||
| `mac_stock_financial` | 财务指标 | (ts_code, end_date) |
|
||
| `mac_report` | 报告持久化 | id |
|
||
|
||
### DAO (`finance/database/dao.py`)
|
||
|
||
- `_DAILY_COLS` / `_FINA_COLS` — 入库前字段筛选
|
||
- `get_latest_trade_date(ts_code)` → 增量判断
|
||
- `save_report()` / `query_reports()` → 报告管理
|
||
|
||
### 配置
|
||
|
||
```bash
|
||
# SSH 隧道
|
||
bash shared/script/autossh.sh
|
||
# host: 127.0.0.1:13306 user: myquant database: myquant
|
||
```
|
||
|
||
## 缓存策略
|
||
|
||
- `sync_daily`: 已缓存且最新 → 0.04s 跳过
|
||
- 未缓存 → 提示 `agent_cli.py warmup`
|
||
- 每日增量只更新已缓存股票,未缓存统计跳过
|
||
|
||
## ⚠️ 已知 Bug 速查(避免重复踩坑)
|
||
|
||
### B1: `.env` 加载路径
|
||
- **症状**: Tushare available=False, QWEN_API_KEY 读不到
|
||
- **根因**: `load_dotenv()` 不传路径,从 CWD 找 .env,而非 `finance/`
|
||
- **修复**: `config/settings.py` 用 `Path(__file__).parent.parent / ".env"`
|
||
- **加固**: `tushare_source.py`, `qwen_client.py`, `news_source.py` 顶部 `import config.settings`
|
||
|
||
### B2: SSH 重连只生效一次
|
||
- **症状**: 第一次断连能恢复,第二次断连无法恢复
|
||
- **根因**: `_ssh_auto_attempted` 全局变量设 True 后永不重置
|
||
- **修复**: 移除该变量。`get_engine()` 每次断连都触发 `_reconnect_ssh()` → `dispose()` → 重建
|
||
|
||
### B3: 连接池半开连接
|
||
- **症状**: `_test_engine()` 返回 True 但实际查询报 `_read_bytes` 超时
|
||
- **根因**: 池中有活连接也有死连接,test 取到活的,查询取到死的
|
||
- **修复**: `pool_pre_ping=True` + `pool_recycle=600` + 断连时 `_engine.dispose()`
|
||
|
||
### B4: save_daily 主键冲突
|
||
- **症状**: `IntegrityError: Duplicate entry '000001.SZ-20260603'`
|
||
- **根因**: Tushare 返回的数据含已存在的日期,`append` 模式遇主键冲突
|
||
- **修复**: 写入前 `DELETE FROM mac_stock_daily WHERE ts_code IN (...) AND trade_date IN (...)`
|
||
|
||
### B5: 数据不更新排查清单
|
||
- 检查 SSH 隧道: `lsof -i :13306 | grep LISTEN`
|
||
- 检查 Tushare: `python -c "from data.sources.tushare_source import TushareSource; print(TushareSource().available)"`
|
||
- 检查最新数据: `from database.dao import get_latest_trade_date; print(get_latest_trade_date('000001.SZ'))`
|
||
- 手动触发 sync: `dm.sync_daily('000001.SZ')`
|
||
- 预期行为: T+1 数据产出,节假日无新数据属于正常
|