Files
sanguo_quant_live/pangtong-value/research/task-20260430-data-platform-integration/design.md
T
2026-04-30 20:51:54 +08:00

299 lines
10 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 📐 架构设计:整合数据平台与回测环境
**任务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 核心代码