需求规格文档:本地数据源体系建设
任务ID: data-platform-20260502
节点: pangtong_requirements
作者: 庞统(副军师)
日期: 2026-05-02
一、项目背景与核心问题
1.1 现状
| 资产 |
状态 |
位置 |
| NAS日线Parquet |
✅ 2010-2026年全市场,按年分目录 |
/Volumes/stock/A股数据/日线数据/daily/{year}/sh{code}_daily.parquet |
| NAS分钟线Parquet |
⚠️ 仅84只15分钟线 |
/Volumes/stock/minute_kline/15min/sz{code}_15min.parquet |
| vnpy quant_trading.db |
❌ 空库(8KB,0张表) |
/Volumes/stock/sanguo_vnpy/data/quant_trading.db |
| 回测服务 |
✅ 运行中(http://192.168.2.154:8088) |
Docker容器 |
| 本地数据适配器 |
⚠️ 已有但路径硬编码Mac本地 |
vnpy_local_data_adapter.py(指向/Users/chufeng/nas/stock/...) |
1.2 核心问题
vnpy回测服务的数据库是空的,回测引擎 engine.load_data() 从数据库读取数据 → 无数据 → 所有回测任务必然失败。
回测服务executor.py关键代码(L171-175):
如果没有数据,直接抛出 ValueError("无法加载历史数据")。
1.3 目标
打通 NAS Parquet → vnpy SQLite DB → 回测引擎 的数据通路,让回测服务可以正常执行回测任务。
二、功能需求
P1:打通vnpy数据通路
P1-1:确认Docker volume映射路径
| 项 |
说明 |
| 需求 |
确认Mac写入的文件,Docker容器内能读到 |
| 输入 |
NAS目录结构、Docker容器配置 |
| 输出 |
明确的映射关系文档:Mac路径 ↔ 容器内路径 |
| 验证 |
在Mac写入测试文件,容器内能读到;反之亦然 |
关键证据:
- 回测服务配置
base_dir = "/app/backtest_jobs"
- 数据目录
data_dir = settings.base_dir.replace("backtest_jobs", "data") → /app/data
- quant_trading.db 位于
/Volumes/stock/sanguo_vnpy/data/
- 需确认Docker容器启动时是否挂载了
/Volumes/stock/sanguo_vnpy/data → /app/data
P1-2:编写vnpy DB导入脚本
| 项 |
说明 |
| 需求 |
将NAS日线Parquet数据批量导入vnpy SQLite数据库 |
| 输入 |
/Volumes/stock/A股数据/日线数据/daily/{year}/sh{code}_daily.parquet |
| 输出 |
quant_trading.db 中有完整的日线bar数据 |
| 验证 |
回测引擎 load_data() 能读出数据 |
| 约束 |
幂等操作(INSERT OR REPLACE),可重复执行 |
vnpy DB Schema要求(待姜维确认):
- vnpy 4.x的BacktestingEngine通过
MainEngine + BaseDataManager 加载数据
- 数据表名和字段名由vnpy内部定义
- 必须先搞清楚vnpy 4.x期望的数据库结构,再写导入脚本
Parquet字段:
导入脚本功能要求:
- 扫描
/Volumes/stock/A股数据/日线数据/daily/ 下所有年份目录
- 每个Parquet文件解析股票代码(从文件名提取,如
sh600000 → 600000.SSE)
- 转换为vnpy DB格式并批量写入
- 支持增量导入(只导入新增数据)
- 支持断点续传(中断后可继续)
- 记录导入日志(成功/失败数、耗时)
P1-3:全量导入日线
| 项 |
说明 |
| 需求 |
运行导入脚本,将全市场2010-2026年日线数据全部导入 |
| 输入 |
P1-2的导入脚本 + NAS日线Parquet |
| 输出 |
quant_trading.db 填满日线数据 |
| 验证 |
统计导入记录数,抽查几只股票确认数据完整 |
| 风险 |
导入耗时长(预估2-4小时),需支持断点续传 |
P1-4:验证回测服务可用
| 项 |
说明 |
| 需求 |
提交一个简单回测任务,确认回测引擎能加载数据并完成回测 |
| 输入 |
回测服务API + 简单策略代码 |
| 输出 |
回测成功返回统计结果 |
| 验证 |
total_trades > 0 或 total_days > 0 |
P2:数据基础设施
P2-1:多源降级管理器 fallback.py
| 项 |
说明 |
| 需求 |
统一数据获取入口,支持多数据源顺序降级 |
| 降级链(日线) |
akshare stock_zh_a_hist → 腾讯K线API |
| 降级链(实时) |
新浪实时 → 东方财富 → 腾讯 |
| 接口 |
get_daily(symbol, start, end) / get_realtime(symbol) |
| 行为 |
第一个源失败自动切下一个,记录使用的源 |
| 产出 |
~150行 |
P2-2:数据校验层 validator.py
| 项 |
说明 |
| 需求 |
入库前校验数据质量,fatal级拒绝入库 |
| V1规则(7条fatal) |
D1: close/open/high/low > 0;D2: OHLC一致性(high≥max(open,close), low≤min(open,close));D3: volume ≥ 0;D6: 同股同日不重复;D7: date ≤ 今天;R1: 实时价格 > 0;R7: 必须携带source+fetched_at |
| 接口 |
validate(df) → (passed: bool, errors: List[str]) |
| 产出 |
~150行 |
P2-3:实时行情三源降级 realtime.py
| 项 |
说明 |
| 需求 |
获取实时行情,支持3个源降级 |
| 降级链 |
新浪实时 → 东方财富 → 腾讯 |
| 接口 |
get_realtime_quote(symbol) → dict |
| 产出 |
~200行 |
P2-4:增量更新 updater.py
| 项 |
说明 |
| 需求 |
每日增量更新,Parquet+vnpy DB双写 |
| 流程 |
1.获取最新日期 2.拉取增量数据 3.校验 4.写Parquet(原子:临时文件+rename) 5.写vnpy DB(INSERT OR REPLACE幂等) 6.一致性校验 |
| 约束 |
Parquet是真相源;vnpy DB失败不影响Parquet |
| 接口 |
update_daily() → UpdateResult |
| 产出 |
~150行 |
P2-5:cron定时任务
| 项 |
说明 |
| 需求 |
每交易日15:30自动执行增量更新 |
| 配置 |
Mac crontab(Mac已确认永不休眠) |
| 验证 |
下一个交易日检查是否自动执行 |
P3:分钟线数据
P3-1:P0限频验证
| 项 |
说明 |
| 需求 |
验证腾讯API限频阈值 |
| 测试1 |
100只股票15分钟线连续下载,是否成功 |
| 测试2 |
连续1小时请求,记录每分钟成功次数、封禁恢复时间 |
| 输出 |
限频验证报告(每分钟最大请求数、封禁时长、恢复策略) |
| 决策 |
报告决定P3-2/P3-3的实现策略(分批间隔、每批数量) |
P3-2/P3-3:分钟线全量下载
| 项 |
说明 |
| 需求 |
下载HS300/全市场15分钟线 |
| 前置 |
P3-1限频验证通过 |
| 数据源 |
腾讯mkline API(唯一可用源,akshare分钟线已失效) |
| 存储路径 |
/Volumes/stock/minute_kline/15min/ |
| 约束 |
15分钟线优先,1分钟线暂缓 |
P3-4:分钟线导入vnpy DB
| 项 |
说明 |
| 需求 |
将分钟线Parquet导入vnpy DB |
| 前置 |
P1-2已确认vnpy DB Schema + 分钟线Parquet已下载 |
| 不确定项 |
vnpy 4.x如何区分不同周期(15min vs 1min)的分钟线 |
P4:配套skill与自动化
P4-1/P4-2:更新skill文档
更新 data-acquisition 和 quant-backtest SKILL.md,补充vnpy数据通路说明。
P4-3:全量校验脚本
关羽设计的V2规则(14条),用于定期全量扫描。
P4-4:周维护cron
每周校验Parquet与vnpy DB一致性。
三、交付物清单
代码文件(放到 ~/.openclaw/sanguo_projects/sanguo_vnpy/data_platform/)
| 文件 |
功能 |
阶段 |
预估行数 |
import_vnpy.py |
Parquet → vnpy DB 导入 |
P1 |
~200 |
fallback.py |
多源降级管理器 |
P2 |
~150 |
validator.py |
数据校验(V1 7条fatal) |
P2 |
~150 |
realtime.py |
实时行情三源降级 |
P2 |
~200 |
updater.py |
增量更新(双写) |
P2 |
~150 |
validate_full.py |
全量校验(V2 14条) |
P4 |
~100 |
文档文件
| 文件 |
内容 |
位置 |
| 需求规格文档 |
本文档 |
docs/data-platform/01-requirements.md |
| 设计方案文档 |
接口设计、数据流、Schema映射 |
docs/data-platform/02-design.md |
| 验证报告 |
限频验证、导入验证、回测验证 |
docs/data-platform/reports/ |
配置文件
| 文件 |
内容 |
| crontab配置 |
每日15:30增量更新 |
| vnpy DB路径映射 |
Mac ↔ Docker |
四、假设与不确定项
| # |
假设/不确定项 |
影响范围 |
验证人 |
验证时机 |
| 1 |
Docker volume映射:Mac写入NAS的文件Docker容器能读到 |
P1全部 |
姜维 |
P1开始前 |
| 2 |
vnpy 4.x DB Schema:回测引擎load_data()期望的表结构和字段 |
P1-2, P3-4 |
姜维 |
P1开始前 |
| 3 |
vnpy分钟线周期区分:vnpy如何存储/区分不同粒度分钟线 |
P3-4 |
姜维 |
P3开始前 |
| 4 |
腾讯API限频:连续请求的频率上限和封禁恢复时间 |
P3全部 |
赵云 |
P3开始前 |
| 5 |
全量导入耗时:5500只×17年数据的导入时间 |
P1-3 |
张飞/赵云 |
P1-3执行时 |
| 6 |
SQLite并发:cron写入+回测读取是否冲突 |
P2-5 |
姜维 |
P2-5配置时 |
| 7 |
NAS存储空间充足(1.5TB可用,只需28GB) |
全局 |
已确认 |
- |
| 8 |
Mac永不休眠(cron可靠执行) |
P2-5 |
已确认 |
- |
| 9 |
不引新依赖(只用akshare+urllib+已有库) |
全局 |
约束 |
- |
关键阻塞项:#1和#2如果不明确,P1无法开始。建议姜维先验证这两项。
五、约束
- 所有产出放到
~/.openclaw/sanguo_projects/sanguo_vnpy/ 目录下
- 不引新依赖(只用akshare + urllib + 已有的库)
- 不改Docker/NAS配置,数据通过volume映射
- Parquet是唯一真相源,vnpy DB是可重建的派生缓存
- 双写顺序:先Parquet(原子写入)→ 再vnpy DB(幂等写入)
- 腾讯API是唯一可用的分钟线源
- 15分钟线优先,1分钟线暂缓
- 不确定项遇到阻塞时,用最大尝试轮数限制,不无限重试
- 每个阶段先输出需求和设计方案,经评审再编码
六、成功标准
| # |
标准 |
验证方法 |
| 1 |
vnpy DB有全市场日线数据 |
SELECT count(*) FROM ... > 0 |
| 2 |
回测服务能完成一次完整回测 |
提交回测任务返回成功 |
| 3 |
增量更新可自动执行 |
crontab触发后日志显示成功 |
| 4 |
数据校验拦截bad data |
构造异常数据,校验返回fatal |
| 5 |
多源降级正常工作 |
关掉主源,自动切到备用源 |
| 6 |
分钟线P0验证有结论 |
限频报告有明确数字 |
七、数据流架构