diff --git a/docs/data-platform/daily-update-design.md b/docs/data-platform/daily-update-design.md index 79b80c1f..d9d438b9 100644 --- a/docs/data-platform/daily-update-design.md +++ b/docs/data-platform/daily-update-design.md @@ -2,9 +2,9 @@ **项目**: sanguo_vnpy 数据平台 **作者**: 赵云(数据总管) -**日期**: 2026-05-03 -**版本**: v1.1 -**状态**: 评审通过,代码已修改 +**日期**: 2026-05-06 +**版本**: v2.0 +**状态**: 待评审(重大架构变更) --- @@ -530,12 +530,13 @@ sanguo_vnpy/ | 2026-05-03 | v1.0-draft | 初始版本 | 赵云 | | 2026-05-03 | v1.1 | 司马懿评审后修改:interval→15m, 严格增量追加, 日线进度文件, 全局源检测, DB轮转备份, 失败率告警 | 赵云 | | 2026-05-05 | v1.2 | 东方财富集成:日线主源切换为东方财富(amount真实,反爬策略4s/请求+随机抖动), 腾讯降为备源 | 赵云 | +| 2026-05-06 | v2.0 | **重大架构变更**:BaoStock替代所有主源(无反爬、全量历史、amount真实);15min interval改为1m;vnpy DB写入改为本地构建+rsync;新浪API已挂移除;多源fallback机制重构 | 赵云 | --- ## 十三、评审结果(2026-05-03 司马懿评审) -### 评审结论:有条件通过 +### v1.1 评审结论:有条件通过(已完成) **2个阻塞项(已解决)**: 1. ✅ interval="1m" → "15m":采用方案B(vnpy加MINUTE_15枚举 + monkey patch) @@ -547,12 +548,207 @@ sanguo_vnpy/ 3. ✅ DB轮转备份(保留7天,`quant_trading_{YYYYMMDD}.db.bak`) 4. ✅ 失败率>5%告警标记 + 源终止告警 -**8个待评审项确认**: -1. SMB性能:V1方案A(Mac→SMB),V1.1切方案B(NAS本地执行) -2. DB同步Docker:V1手动,V2用cron job -3. 数据源标记:V1不加 -4. amount为0:V1保留腾讯0值,记录告警 -5. interval:已改为"15m" -6. 部署整合:P2不急 -7. DB备份:已实现轮转备份 -8. 错误告警:已实现失败率阈值 +--- + +## 十四、v2.0 重大架构变更(2026-05-06) + +### 14.1 变更背景 + +v1.2运行暴露了5个根本性问题: + +| # | 问题 | 根因 | 影响 | +|---|------|------|------| +| 1 | vnpy DB写入报`no such table: dbbardata` | SMB文件锁与SQLite ATTACH不兼容 | 日线+15min数据不入DB | +| 2 | 新浪15min API已失效 | 返回Error 0,所有请求失败 | 15min无法增量更新 | +| 3 | BaoStock 15min回补已完成但未入库 | 原脚本interval=`15m`与vnpy不兼容 | 5193只×8992条数据闲置 | +| 4 | 日线跨年写入bug | `year=datetime.now().year`硬编码 | 年初数据会写错目录 | +| 5 | overview全表聚合 | 1.4G DB上GROUP BY全表扫描 | NAS上可能超时/锁死 | + +### 14.2 数据源重新调研 + +#### 数据源实测对比 + +| 数据源 | 15min可获取量 | 日线可获取量 | amount | 反爬 | 频率 | 当前状态 | +|--------|-------------|-------------|--------|------|------|----------| +| **BaoStock** | 无限制(按日期) | 无限制(按日期) | 真实(5.54亿) | **无** | 0.12s/只, 100只0错误 | ✅ 稳定 | +| **东方财富** | ~496条(7周) | 多年(~1046条) | 真实(5.54亿) | 4-5s/请求+UA+Referer | 中 | ✅ 可用 | +| **腾讯** | Connection reset | 按日期范围 | 有时为0 | 无 | 快 | ⚠️ 不稳定 | +| **新浪** | Error/2条 | Error/2条 | - | - | - | ❌ 已挂 | + +**关键结论**:BaoStock在所有维度都最优(无反爬、全量历史、amount真实、速度快),应作为首选源。 + +#### v1.2 BaoStock压力测试 + +``` +15min: 100只连续请求, 总耗时11.9s, 平均0.12s/只, 0错误 +日线: 10只连续请求, 总耗时1.6s, 平均0.16s/只 +全历史: sh.600000 2010-2026日线 3963条, 0.68s +``` + +#### v1.2 SQLite本地写入性能 + +``` +100万条INSERT OR REPLACE: 2.0s +预估4600万条(15min全量): ~91s ≈ 1.5分钟 +``` + +### 14.3 v2.0 核心架构变更 + +#### 变更1:数据源降级链重构 + +**设计原则**:按数据质量排序,质量最好的源排第一。每个源封装独立函数,统一返回DataFrame。主循环挨个尝试,成功即用,失败试下一个。 + +``` +v1.x(旧): + 日线: 腾讯(主) → 新浪(备) + 15min: 新浪(主) → 无备源 + +v2.0(新): + 日线: BaoStock(主) → 东方财富(备) → 腾讯(三备) + 15min: BaoStock(主) → 东方财富(备) → 新浪(三备,当前已挂) +``` + +**Fallback机制**: +```python +SOURCES_DAILY = [ + ("baostock", fetch_baostock_daily), # 最优:全量历史+无反爬+amount真实 + ("eastmoney", fetch_eastmoney_daily), # 备用:多年历史+amount真实+4s限频 + ("tencent", fetch_tencent_daily), # 三备:amount有时为0 +] +SOURCES_15MIN = [ + ("baostock", fetch_baostock_15min), # 最优 + ("eastmoney", fetch_eastmoney_15min), # 备用:7周 + ("sina", try_sina_15min), # 三备:当前已挂 +] + +def fetch_with_fallback(sources, code, start, end): + for name, fetch_fn in sources: + try: + data = fetch_fn(code, start, end) + if data is not None and len(data) > 0: + return data, name + except Exception: + continue + return None, None +``` + +#### 变更2:vnpy DB写入策略改为本地构建+rsync + +**v1.x方案(ATTACH via SMB)**:直接在Mac上ATTACH NAS DB → SMB文件锁导致失败 + +**v2.0方案(本地构建+rsync)**: +1. 每日更新时,从NAS cp当前DB到本地`/tmp/` +2. 所有增量数据写入本地DB +3. 验证完整性后,rsync覆盖NAS DB +4. 备份旧DB(轮转7天) + +```python +def sync_db_to_nas(): + # 备份 + backup = f"quant_trading_{today}.db.bak" + shutil.copy2(str(VNPY_DB_PATH), str(VNPY_DB_PATH.parent / backup)) + + # rsync本地→NAS + os.system(f"rsync -av --progress {LOCAL_DB_PATH} {VNPY_DB_PATH}") +``` + +**性能预估**: +- cp NAS DB到本地:~15秒(1.4G) +- 增量写入本地DB:<1秒(日线) +- rsync覆盖NAS:~15秒 +- 全量15min导入(首次):~1.5分钟(4600万条) + +#### 变更3:15min interval统一用`1m` + +**v1.x**:interval=`15m`(与vnpy 4.x不兼容) +**v2.0**:interval=`1m`(姜维确认vnpy 4.x Interval.MINUTE.value=`1m`) + +**数据格式(姜维确认)**: +- symbol: `000001`(纯代码) +- exchange: `SSE` / `SZSE` +- interval日线: `d` +- interval分钟线: `1m` + +#### 变更4:日线跨年写入修复 + +**v1.x bug**:`year = datetime.now().year`,年初数据写错目录 +**v2.0**:按数据日期分目录 + +```python +def update_daily_parquet(code, new_data): + for yr in new_data["date"].str[:4].unique(): + year_data = new_data[new_data["date"].str[:4] == yr] + parquet_path = DAILY_DIR / yr / f"{prefix}{clean}_daily.parquet" + # 合并写入... +``` + +#### 变更5:overview增量更新 + +**v1.x**:`SELECT ... FROM dbbardata GROUP BY` 全表扫描(1.4G DB上很慢) +**v2.0**:只更新本次涉及的symbol + +```python +for sym, exc, ivl in affected_keys: + c.execute("""INSERT OR REPLACE INTO dbbaroverview + SELECT ?,?,?,COUNT(*),MIN(datetime),MAX(datetime) + FROM dbbardata WHERE symbol=? AND exchange=? AND interval=?""", + (sym, exc, ivl, sym, exc, ivl)) +``` + +#### 变更6:进度文件加日期 + +**v1.x**:进度文件不区分日期,跨天可能跳过 +**v2.0**:`daily_20260506_progress.json`,每次运行独立进度 + +#### 变更7:Cron fallback模型 + +**v1.x**:只用默认模型,配额用完则任务失败 +**v2.0**:设置fallback模型(zhipu/glm-5.1),配额不足时自动降级 + +### 14.4 执行计划 + +#### 第1步:灌入现有数据到本地vnpy DB + +``` +1. cp NAS quant_trading.db → /tmp/quant_trading_import.db +2. import_vnpy_daily_fast.py --start-year 2026 # 补3/28~今天的日线增量 +3. import_vnpy_minute.py --scope all # 全量导入5193只15min +4. 验证数据完整性 +5. rsync本地DB → NAS +``` + +#### 第2步:重构daily_all_update.py + +按14.3的7个变更点重构代码。 + +#### 第3步:Cron更新+测试 + +- 更新cron任务配置 +- 手动触发一次全量更新验证 +- 确认日志无错误 + +### 14.5 与v1.x的兼容性 + +| 变更 | 向后兼容 | 影响 | +|------|---------|------| +| interval 15m→1m | ❌ 需要DB迁移 | 现有15m数据需UPDATE为1m | +| DB写入策略 | ✅ 无影响 | Parquet不受影响 | +| 数据源顺序 | ✅ 无影响 | 只是重试顺序变化 | +| 跨年写入 | ✅ 修正bug | 未来数据不再错 | +| overview增量 | ✅ 无影响 | 只是优化 | + +> ⚠️ **DB迁移注意**:v1.x如果有`interval='15m'`的记录,需要一次性UPDATE为`'1m'`。当前DB中实际无15min数据(v1.x的写入全部失败),所以无需迁移。 + +--- + +## 十五、v2.0 评审待确认项 + +| # | 问题 | 建议方案 | 待确认 | +|---|------|---------|--------| +| 1 | BaoStock作为全主源是否合适? | 无反爬+全量+amount真实,建议通过 | 司马懿 | +| 2 | 本地构建+rsync替代ATTACH | 姜维确认推荐,比ATTACH稳定 | 司马懿 | +| 3 | interval=1m而非15m | 姜维确认vnpy 4.x规范 | 司马懿 | +| 4 | 是否需要DB迁移脚本? | 当前无15m数据,无需迁移 | 司马懿 | +| 5 | Fallback顺序是否合理? | BaoStock→东方财富→腾讯/新浪 | 司马懿 | +| 6 | 日常更新全市场耗时预估? | BaoStock: ~10min(15min)+~8min(日线)+rsync | 司马懿 | +| 7 | 是否需要额外反爬措施? | BaoStock无需,备源保留原有措施 | 司马懿 |