# 数据架构方案A迁移 + schtask 改造 实施计划 > **For agentic workers:** REQUIRED SUB-SKILL: superpowers:executing-plans。Steps use checkbox。 **Goal:** 落地 spec §14 方案A定稿 — DB 唯一表、每类数据唯一权威源、4 个新 schtask、迁移 5 单元,全程备份+staging+可回滚+审计。 **Architecture:** 以本地 DB 迁移为主(`daily_baostock_full`→dbbardata/parquet,无网络),schtask 改造(废弃旧 4 个新建 4 个)。每单元独立可回滚,按风险升序。 **Tech Stack:** Python3.10 / sqlite3(WAL) / pandas parquet / Windows schtasks / baostock+xtata+akshare ## Global Constraints - baostock:单进程单登录,`DAILY_LIMIT=48000`,sleep 限速,login 探针 graceful skip,直连不走代理(unset proxy) - xtata:单进程 download 不并发,无限流 - akshare:interval 4s 单线程,防东财封 IP - 每迁移单元前:`sqlite3 .backup` 全库 + rsync 到 NAS `/volume1/stock/backup/` + WAL checkpoint - 每单元:staging 隔离 → 验证探针 → 用户确认合并 → 旧 rename `_old` 保留 7 天 - 全程 nohup + 审计日志 `data/migration_logs/_.log` - 不破坏 vnpy 回测:dbbardata schema 不动(只灌数据),`dbbardata` 12 列保持 ## 文件结构 - 迁移脚本:`scripts/data_platform/migrate_*.py`(每单元一个) - 验证脚本:`scripts/data_platform/verify_*.py` - schtask wrapper:`scripts/data_platform/*_wrapper.ps1` - 审计日志:`data/migration_logs/` --- ## 前置 Task 0:全库备份(所有单元前必做) **Files:** `scripts/data_platform/backup_db.py`(新建,可复用) - [ ] 写脚本:`sqlite3 .backup` → `quant_trading.db.bak_`(在线一致);WAL checkpoint;rsync 到 NAS - [ ] 执行 - [ ] **verify**:`.bak` 存在 + 大小≈28GB + `PRAGMA integrity_check` ok --- ## 单元 1:存量垃圾清理(零风险) **Files:** `scripts/data_platform/cleanup_staging.py`(新建) - [ ] 写脚本:`--dry-run` 先列清单 → 删 `_staging_xtdata/`(14万)、`_xtdata.tar`(1.4G);移 `cta_*/dbg_*/smoke_*/trace_*` → `backtest_files/` - [ ] dry-run 输出清单给用户确认 - [ ] 执行删除/移动 - [ ] **verify**:`data/` 根目录无散落 json/log;`backtest_files/` 收纳;`du -sh data/` 体积下降 - [ ] **回滚**:staging 可由 `build_daily_from_xtdata` 重建(已合并到 qfq/raw) --- ## 单元 2:config 统一 VPS 路径 **Files:** `config/data_platform.yaml`(VPS 实例) - [ ] 核实 VPS 实际 config 路径(当前仓库版指 NAS /volume1,是容器版遗留) - [ ] `daily_dir/raw_dir/qfq_dir/minute_15_dir` → `C:\sanguo_vnpy_v2\data\...` - [ ] `daily_dir` 统一指 qfq(消除 `daily/` vs `qfq/` 分叉,`daily/`68文件归档) - [ ] NAS config 保留 + 注释"备份用" - [ ] **verify**:`datareader.read_parquet_daily` 抽样能读 + LocalParquetProvider 抽样 - [ ] **回滚**:yaml 改回 --- ## 单元 3:成份股合并 → `constituent_unified` **Files:** `scripts/data_platform/migrate_constituent.py` + `verify_constituent.py` **Interfaces:** 读 `bs_index_constituent`(baostock 300/500/50)+ `data/index_const_hist/*_union.parquet`(akshare cni 深证);写 `constituent_unified(date,index_code,code,code_name,source)` - [ ] 写迁移脚本:按指数代码去重(300/500/50=baostock;深证 399xxx=akshare cni union;新浪 300/50 作校验丢弃);schema 映射 INSERT - [ ] staging:先写 `constituent_unified_staging` - [ ] **verify**:行数 / 指数覆盖 / 抽样某指数某日成份集 vs 源一致 / 无同指数同日重复 - [ ] 合并:rename staging → `constituent_unified`;`bs_index_constituent` → `_old` - [ ] 7 天后删 `_old` - [ ] **回滚**:rename `bs_index_constituent_old` 回来 --- ## 单元 4:`daily_baostock_full` 拆分(本地 DB 迁移,无网络) **Files:** `scripts/data_platform/migrate_daily_baostock.py` + `verify_daily_migration.py` **Interfaces:** 读 `daily_baostock_full`(含退市);写 `dbbardata('d')`(OHLCV 12 列)+ `data/valuation_baostock/.parquet` - [ ] 写迁移脚本: - OHLCV:`daily_baostock_full` → dbbardata INSERT OR REPLACE(interval='d',exchange SH/SZ→SSE/SZSE,datetime=date)。含退市(治偏差)。ETF 不碰(已在 dbbardata) - pe/pb:按年 group → `valuation_baostock/.parquet` 宽表 - [ ] staging:先写 `dbbardata_staging_daily` 表 + parquet staging 目录,不动 dbbardata - [ ] **verify**: - 退市股(000005 等)在 dbbardata('d') 有了(治偏差验证) - 在市股(600519)日线行数 / 抽样价格 vs daily_baostock_full 一致 - pe/pb parquet 按年覆盖 + 抽样值合理 - dbbardata 总行数变化合理(+退市日线) - [ ] 合并:staging → dbbardata;`daily_baostock_full` → `_old`;valuation parquet → 正式目录 - [ ] 7 天后删 `_old` - [ ] **回滚**:`daily_baostock_full_old` 还原 + dbbardata 从 `.bak` 恢复 --- ## 单元 5:schtask 改造(废弃旧 4 个,新建 4 个) **Files:** `scripts/data_platform/bs_eod.py`(日线+15min+pe/pb 拆)+ `xt_eod.py`(ETF+实时)+ `*_wrapper.ps1` - [ ] 写 `bs_eod.py`:基于 `daily_update_static.py` 扩展,+15min 增量,+pe/pb 拆 parquet;落 dbbardata('d'/'15m');`DAILY_LIMIT=48000` - [ ] 写 `xt_eod.py`:基于 `daily_update_xtdata.py`,universe 收窄 ETF/基金 + 个股当天实时;落 dbbardata('d') - [ ] **verify**:`--limit 10` 小样本跑通 + 数据到当天 - [ ] 部署 schtask:废弃 `sanguo-daily-update`/`sanguo-bs-daily-increment`/`sanguo-index-hist`;新建 `sanguo-bs-eod`(18:05)/`sanguo-xt-eod`(18:40);`sanguo-bs-akshare` 调到 19:00;`sanguo-index`(月度 19:50) - [ ] **verify**:`schtasks /query` + 首日运行结果码 + 数据抽查到当天 - [ ] **回滚**:重新注册旧 schtask --- ## 收尾:E2E 验证 - [ ] 回测 all_weather 一轮(读 dbbardata 日线含退市 + valuation parquet + constituent_unified)无回归 - [ ] LocalParquetProvider 接 constituent_unified + valuation_baostock 单测 - [ ] 更新 memory:`data-fusion-design-finalized`(标方案A落地)+ 新建 `data-arch-migration-done` ## 执行节奏 - 每单元独立提交 + 用户 review staging 再合并(单元 4/5 关键) - 全程 VPS nohup 跑(Mac Mini 防休眠 caffeinate,长迁移) - 顺序:0 → 1 → 2 → 3 → 4 → 5 → 收尾(严格风险升序)