From 8d1e917b50a0408521cd2d3c3e5d71abc819b8e8 Mon Sep 17 00:00:00 2001 From: cfdaily Date: Thu, 30 Apr 2026 20:51:54 +0800 Subject: [PATCH] auto-sync: 2026-04-30 20:51:54 --- .../design.md | 298 ++++++++++++++++++ 1 file changed, 298 insertions(+) create mode 100644 pangtong-value/research/task-20260430-data-platform-integration/design.md diff --git a/pangtong-value/research/task-20260430-data-platform-integration/design.md b/pangtong-value/research/task-20260430-data-platform-integration/design.md new file mode 100644 index 000000000..8fb0f6ad5 --- /dev/null +++ b/pangtong-value/research/task-20260430-data-platform-integration/design.md @@ -0,0 +1,298 @@ +# 📐 架构设计:整合数据平台与回测环境 + +**任务ID**: integrate-data-platform-20260430 +**撰写人**: 庞统 +**日期**: 2026-04-30 + +--- + +## 一、现状分析 + +### 数据资产清单 + +| 数据类型 | 格式 | 存储位置 | 文件组织 | 数量 | +|----------|------|---------|---------|------| +| 日线行情 | Parquet | `raw/daily/{year}/{code}_daily.parquet` | 按年分目录 | 2013-2025 | +| 财务估值 | Parquet | `raw/financial/valuation/{code}_valuation.parquet` | 按类型分目录 | ~5000股 | +| 股票信息 | CSV | `raw/stock_info/stock_basic_info_*.csv` | 单文件 | 5493股 | +| HS300成分 | CSV | `raw/stock_info/hs300_constituents_latest.csv` | 单文件 | 300只 | +| 日线(旧) | Parquet | `raw/a_stock_daily/{year}/` | 按年分目录,无文件 | 可能为空 | + +### 已有组件 + +| 组件 | 语言 | 接口 | 依赖 | +|------|------|------|------| +| VnpyLocalDataAdapter | Python | 类方法 | akshare | +| backtest-service | Python | REST API (FastAPI) | vnpy | +| 张飞回测框架 | Python | 函数调用 | numpy, pandas | + +### 关键发现 + +1. **数据格式已经是 Parquet**(不是 CSV),字段:`date, open, high, low, close, volume, amount, outstanding_share, turnover, year` +2. **姜维适配器路径硬编码** `/Users/chufeng/nas/stock/sanguo_vnpy/zhaoyun-data/data`,与实际数据路径不同 +3. **a_stock_daily/ 和 daily/ 是两套目录**,需确认哪套是主数据 + +--- + +## 二、架构设计 + +### 核心原则:最简方案 + +**不新建独立包/服务**。直接在现有项目内加一个 `data_platform.py` 配置文件 + 一个 `catalog.py` 数据接口。 + +### 架构图 + +``` +┌─────────────────────────────────────────────────┐ +│ 策略开发者 │ +│ (张飞回测 / vnpy回测 / 未来策略) │ +└───────────────────┬─────────────────────────────┘ + │ 调用 + ▼ +┌─────────────────────────────────────────────────┐ +│ DataCatalog (catalog.py) │ +│ │ +│ get_daily(symbol, start, end) → DataFrame │ +│ get_stock_list() → DataFrame │ +│ get_financial(symbol) → DataFrame │ +│ get_index_constituents(index) → DataFrame │ +└───────────────────┬─────────────────────────────┘ + │ 读取 + ▼ +┌─────────────────────────────────────────────────┐ +│ data_platform_config.yaml │ +│ DATA_ROOT: /path/to/zhaoyun-data/data │ +└───────────────────┬─────────────────────────────┘ + │ 指向 + ▼ +┌─────────────────────────────────────────────────┐ +│ 赵云数据目录 (zhaoyun-data/data/) │ +│ │ +│ raw/daily/{year}/{code}_daily.parquet │ +│ raw/financial/valuation/{code}_valuation.parquet│ +│ raw/stock_info/stock_basic_info_*.csv │ +│ raw/stock_info/hs300_constituents_latest.csv │ +└─────────────────────────────────────────────────┘ +``` + +### 模块划分 + +``` +sanguo_quant_live/ +├── data_platform/ # 🆕 数据平台模块(新建) +│ ├── __init__.py +│ ├── config.py # 配置加载(读 yaml + 环境变量) +│ ├── catalog.py # DataCatalog 核心接口 +│ └── data_platform_config.yaml # 配置文件(DATA_ROOT 等) +├── zhaoyun-data/ # 赵云数据(已有) +│ └── data/raw/... +├── zhangfei-technical/ # 张飞回测(已有) +└── jiangwei-platform/ # 姜维基建(已有) + +sanguo_vnpy/ +└── src/ + └── adapters/ + └── vnpy_local_data_adapter.py # 姜维适配器(改路径配置) +``` + +--- + +## 三、接口定义 + +### data_platform_config.yaml + +```yaml +# 数据平台配置 +data_root: "${ZHAOYUN_DATA_ROOT}" # 优先环境变量 +# 默认值(环境变量未设置时) +default_data_root: "/Users/chufeng/.openclaw/sanguo_projects/sanguo_quant_live/zhaoyun-data/data" + +# 数据源配置 +sources: + daily: + format: parquet + path_pattern: "raw/daily/{year}/{code}_daily.parquet" + date_range: [2013, 2025] + columns: [date, open, high, low, close, volume, amount, outstanding_share, turnover] + + stock_info: + format: csv + path: "raw/stock_info" + file_pattern: "stock_basic_info_*.csv" + + financial: + format: parquet + path_pattern: "raw/financial/valuation/{code}_valuation.parquet" + + index_constituents: + format: csv + path: "raw/stock_info/hs300_constituents_latest.csv" + +# fallback(本地无数据时) +fallback: + enabled: true + provider: akshare +``` + +### config.py + +```python +"""数据平台配置加载""" +import os +import yaml +from pathlib import Path + +def load_config() -> dict: + """加载配置,环境变量优先""" + config_path = Path(__file__).parent / "data_platform_config.yaml" + with open(config_path) as f: + config = yaml.safe_load(f) + + # 环境变量覆盖 data_root + env_root = os.environ.get("ZHAOYUN_DATA_ROOT") + if env_root: + config["data_root"] = env_root + elif "${" in config.get("data_root", ""): + config["data_root"] = config["default_data_root"] + + return config +``` + +### catalog.py 核心接口 + +```python +"""DataCatalog - 统一数据访问接口""" +import pandas as pd +from pathlib import Path +from typing import Optional +from .config import load_config + +class DataCatalog: + def __init__(self, config: dict = None): + self._config = config or load_config() + self._data_root = Path(self._config["data_root"]) + + def get_daily(self, symbol: str, start: str = None, end: str = None) -> pd.DataFrame: + """获取日线行情 + Args: + symbol: 股票代码,如 "000001" 或 "sh600519" + start: 开始日期 "YYYY-MM-DD" + end: 结束日期 "YYYY-MM-DD" + """ + ... + + def get_stock_list(self) -> pd.DataFrame: + """获取全部A股列表""" + ... + + def get_financial(self, symbol: str) -> pd.DataFrame: + """获取财务估值数据""" + ... + + def get_index_constituents(self, index: str = "000300") -> pd.DataFrame: + """获取指数成分股""" + ... +``` + +### stock code 标准化规则 + +``` +输入格式: + "000001" / "sz000001" / "000001.SZ" → 标准化为 "sz000001"(parquet文件名) + "600519" / "sh600519" / "600519.SH" → 标准化为 "sh600519" + +规则: + 0/3 开头 → sz 前缀 + 6 开头 → sh 前缀 + 已有 sh/sz 前缀 → 保持 +``` + +--- + +## 四、数据流设计 + +### 日线数据流 + +``` +赵云采集脚本 → raw/daily/{year}/{code}_daily.parquet + ↓ + DataCatalog.get_daily("600519", "2024-01-01", "2024-12-31") + ↓ + 1. 标准化 code → sh600519 + 2. 扫描 2024/ 目录 + 3. pd.read_parquet("raw/daily/2024/sh600519_daily.parquet") + 4. 按 start/end 过滤日期 + 5. 返回 DataFrame +``` + +### 张飞回测对接 + +``` +# 改前(张飞直接读CSV,硬编码路径) +df = pd.read_csv("/path/to/data.csv") + +# 改后(通过 DataCatalog) +from data_platform import DataCatalog +catalog = DataCatalog() +df = catalog.get_daily("000001", "2024-01-01", "2025-12-31") +``` + +### vnpy适配器对接 + +```python +# 改前(姜维硬编码路径) +ZHAOYUN_DATA_BASE = "/Users/chufeng/nas/stock/sanguo_vnpy/zhaoyun-data/data" + +# 改后(读取 DataCatalog 配置) +from data_platform.config import load_config +config = load_config() +ZHAOYUN_DATA_BASE = config["data_root"] +``` + +--- + +## 五、权衡取舍 + +| 决策 | 选择 | 理由 | +|------|------|------| +| 新建独立包 vs 项目内模块 | **项目内模块** | 代码量小(~200行),不值得独立包 | +| YAML配置 vs JSON | **YAML** | 支持注释,可读性好 | +| Parquet vs CSV | **Parquet(保持现状)** | 已有数据都是Parquet,不改格式 | +| 环境变量 vs 配置文件 | **环境变量优先+配置文件兜底** | 生产环境用环境变量,开发用配置文件 | +| 全量加载 vs 按需加载 | **按需加载(按symbol+日期范围)** | 避免内存浪费 | +| fallback akshare | **保留但默认关闭** | 策略开发者应先确认本地数据完备 | + +--- + +## 六、待澄清项 + +| # | 问题 | 影响范围 | +|---|------|---------| +| Q1 | `raw/a_stock_daily/` 和 `raw/daily/` 是否有重叠?哪个是主数据? | catalog.py 的路径配置 | +| Q2 | 财务数据除了 valuation 还有其他类型吗(income/balance/cashflow)? | get_financial 接口设计 | +| Q3 | 分钟线数据是否纳入本次 DataCatalog? | 是否实现 get_minute() | +| Q4 | NAS 路径 `/Users/chufeng/nas/stock/` 当前是否可用? | vnpy适配器是否能正常工作 | + +--- + +## 七、各角色分工 + +| 角色 | 任务 | 交付物 | +|------|------|--------| +| 赵云 | Q1-Q3 澄清 + 数据目录确认 + 更新SOP | 数据目录说明 + 更新脚本 | +| 张飞 | 回测框架对接 DataCatalog | 修改后的回测代码 | +| 关羽 | 风控数据接口验证 | 风控相关数据接口测试 | +| 姜维 | config.py + catalog.py 实现 + vnpy适配器更新 + 回测环境文档 | 代码 + 文档 | +| 司马懿 | 架构评审 | 评审意见 | +| 庞统 | 整合交付 | 最终报告 | + +--- + +## 八、不做的事 + +1. ❌ 不建数据库 +2. ❌ 不建独立 pip 包 +3. ❌ 不做实时行情 +4. ❌ 不做 Web UI +5. ❌ 不做云端部署 +6. ❌ 不改 vnpy 核心代码