refactor(archive): move unused modules to archive/
Archive legacy framework and utility modules that are no longer referenced by the active core (datasource/ and rotation/): - framework/ -> archive/framework/ - framework_v2/ -> archive/framework_v2/ - strategies/ -> archive/strategies/ - config/ -> archive/config/ - visualization/ -> archive/visualization/ - scripts/ -> archive/scripts/ - tests/ -> archive/tests/ - run_rotation.py, run_us_rotation.py -> archive/single_files/ - compare_*.py, test_api_dates.py -> archive/single_files/
This commit is contained in:
573
archive/framework_v2/config/CONFIG_DESIGN.md
Normal file
573
archive/framework_v2/config/CONFIG_DESIGN.md
Normal file
@@ -0,0 +1,573 @@
|
||||
# V2 配置设计文档
|
||||
|
||||
## 概述
|
||||
|
||||
framework_v2 的配置系统基于 **Pydantic Schema 验证**,解决 V1 配置文件的 10 个问题。
|
||||
|
||||
---
|
||||
|
||||
## 核心设计原则
|
||||
|
||||
### 1. **类型安全**(解决 V1 问题 #2)
|
||||
|
||||
```python
|
||||
# ❌ V1: 无验证
|
||||
n_days: 25 # 如果是 "25"(字符串)会静默失败
|
||||
|
||||
# ✅ V2: Pydantic 验证
|
||||
class FactorConfig(BaseModel):
|
||||
n_days: int = Field(default=25, ge=5, le=250)
|
||||
```
|
||||
|
||||
**验证效果**:
|
||||
```python
|
||||
# 错误:超出范围
|
||||
factor: {n_days: 1000}
|
||||
# → ValidationError: n_days 必须在 5-250 之间
|
||||
|
||||
# 错误:类型错误
|
||||
factor: {n_days: "25"}
|
||||
# → ValidationError: n_days 必须是整数
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 2. **敏感信息环境变量化**(解决 V1 问题 #1)
|
||||
|
||||
```yaml
|
||||
# ❌ V1: 硬编码
|
||||
flask_api:
|
||||
url: "https://k3s.tokenpluse.xyz"
|
||||
ssh_tunnel:
|
||||
host: "8.218.167.69"
|
||||
key_path: "hk_ecs.pem"
|
||||
|
||||
# ✅ V2: 环境变量
|
||||
data:
|
||||
sources:
|
||||
- type: "flask_api"
|
||||
url: "${FLASK_API_URL}" # 从环境变量读取
|
||||
- type: "tushare"
|
||||
token: "${TUSHARE_TOKEN}" # 从环境变量读取
|
||||
```
|
||||
|
||||
**环境变量替换**:
|
||||
```python
|
||||
# 支持格式
|
||||
${VAR_NAME} # 必需环境变量
|
||||
${VAR_NAME:default_value} # 带默认值
|
||||
|
||||
# 示例
|
||||
url: "${FLASK_API_URL}" # 必须设置
|
||||
timeout: "${TIMEOUT:120}" # 默认 120
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 3. **资产池按类别分组**(解决 V1 问题 #3)
|
||||
|
||||
```yaml
|
||||
# ❌ V1: 混合在一起
|
||||
code_list:
|
||||
"399006.SZ":
|
||||
name: "创业板指"
|
||||
market: "A"
|
||||
"GC=F":
|
||||
name: "黄金"
|
||||
market: "COMMODITY"
|
||||
|
||||
# ✅ V2: 按类别分组
|
||||
asset_pools:
|
||||
equity: # 股票资产
|
||||
"399006.SZ":
|
||||
name: "创业板指"
|
||||
market: "CN_EQUITY"
|
||||
"NDX":
|
||||
name: "纳指100"
|
||||
market: "US_EQUITY"
|
||||
|
||||
commodity: # 商品资产
|
||||
"GC=F":
|
||||
name: "黄金"
|
||||
market: "COMMODITY"
|
||||
|
||||
fixed_income: # 固定收益
|
||||
"931862.CSI":
|
||||
name: "短债指数"
|
||||
market: "FIXED_INCOME"
|
||||
```
|
||||
|
||||
**优势**:
|
||||
- ✅ 清晰的资产分类
|
||||
- ✅ 支持分散化策略(每类选 Top-N)
|
||||
- ✅ 易于扩展新资产类别
|
||||
|
||||
---
|
||||
|
||||
### 4. **精简注释 + 独立文档**(解决 V1 问题 #4)
|
||||
|
||||
```yaml
|
||||
# ❌ V1: 30 行注释
|
||||
# 931862.CSI = 中证0-9个月国债指数(短债指数)
|
||||
# 数据范围:2007-12-31开始,约19年数据
|
||||
# 久期:极短(<1年),波动极小,熊市防御效果最佳
|
||||
# ...(共 30 行)
|
||||
"931862.CSI":
|
||||
name: "短债指数"
|
||||
etf: null
|
||||
market: "BOND"
|
||||
|
||||
# ✅ V2: 精简注释 + description 字段
|
||||
fixed_income:
|
||||
"931862.CSI":
|
||||
name: "短债指数"
|
||||
etf: null
|
||||
market: "FIXED_INCOME"
|
||||
description: "中证0-9个月国债指数,久期<1年,防御配置"
|
||||
```
|
||||
|
||||
**详细文档独立**:
|
||||
```
|
||||
docs/
|
||||
├── bond_analysis.md # 债券收益归因分析
|
||||
├── asset_pool_design.md # 资产池设计说明
|
||||
└── threshold_strategy.md # 阈值策略文档
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 5. **统一阈值配置**(解决 V1 问题 #6)
|
||||
|
||||
```yaml
|
||||
# ❌ V1: V2 + V3 共存,逻辑混乱
|
||||
min_score: 0.0 # V2 固定阈值
|
||||
|
||||
bond_threshold: # V3 动态阈值
|
||||
enabled: true
|
||||
bond_code: "931862.CSI"
|
||||
ratio: 1.0
|
||||
fill_bond: true
|
||||
|
||||
# ✅ V2: 统一配置
|
||||
rotation:
|
||||
threshold:
|
||||
mode: "dynamic" # 阈值模式: fixed / dynamic
|
||||
fixed_value: 0.0 # mode=fixed 时使用
|
||||
|
||||
dynamic: # mode=dynamic 时使用
|
||||
reference: "931862.CSI" # 参考标的
|
||||
ratio: 1.0 # 倍数
|
||||
fallback_enabled: true # 回退开关
|
||||
fallback_value: 0.0 # 回退值
|
||||
```
|
||||
|
||||
**模式切换**:
|
||||
```yaml
|
||||
# 固定阈值模式
|
||||
threshold:
|
||||
mode: "fixed"
|
||||
fixed_value: 0.0
|
||||
|
||||
# 动态阈值模式
|
||||
threshold:
|
||||
mode: "dynamic"
|
||||
dynamic:
|
||||
reference: "931862.CSI"
|
||||
ratio: 1.0
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 6. **标准化市场类型**(解决 V1 问题 #8)
|
||||
|
||||
```yaml
|
||||
# ❌ V1: 随意定义
|
||||
market: "A" # A股
|
||||
market: "US" # 美股
|
||||
market: "JP" # 日本
|
||||
|
||||
# ✅ V2: 标准枚举
|
||||
market: "CN_EQUITY" # 中国股票
|
||||
market: "US_EQUITY" # 美国股票
|
||||
market: "JP_EQUITY" # 日本股票
|
||||
market: "EU_EQUITY" # 欧洲股票
|
||||
market: "HK_EQUITY" # 香港股票
|
||||
market: "COMMODITY" # 商品
|
||||
market: "FIXED_INCOME" # 固定收益
|
||||
```
|
||||
|
||||
**Python 枚举**:
|
||||
```python
|
||||
class MarketType(str, Enum):
|
||||
CN_EQUITY = "CN_EQUITY"
|
||||
US_EQUITY = "US_EQUITY"
|
||||
JP_EQUITY = "JP_EQUITY"
|
||||
EU_EQUITY = "EU_EQUITY"
|
||||
HK_EQUITY = "HK_EQUITY"
|
||||
COMMODITY = "COMMODITY"
|
||||
FIXED_INCOME = "FIXED_INCOME"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 7. **多数据源降级策略**(解决 V1 问题 #9)
|
||||
|
||||
```yaml
|
||||
# ❌ V1: 扁平化配置
|
||||
flask_api:
|
||||
enabled: true
|
||||
url: "https://k3s.tokenpluse.xyz"
|
||||
|
||||
ssh_tunnel:
|
||||
enabled: true
|
||||
# ...
|
||||
|
||||
# ✅ V2: 优先级列表
|
||||
data:
|
||||
sources:
|
||||
# 主数据源
|
||||
- type: "flask_api"
|
||||
enabled: true
|
||||
url: "${FLASK_API_URL}"
|
||||
timeout: 120
|
||||
|
||||
# 备用数据源
|
||||
- type: "tushare"
|
||||
enabled: true
|
||||
token: "${TUSHARE_TOKEN}"
|
||||
timeout: 60
|
||||
|
||||
# 降级数据源
|
||||
- type: "yfinance"
|
||||
enabled: false
|
||||
timeout: 120
|
||||
```
|
||||
|
||||
**降级逻辑**:
|
||||
```python
|
||||
for source in config.data.sources:
|
||||
if not source.enabled:
|
||||
continue
|
||||
|
||||
try:
|
||||
data = fetch_from_source(source)
|
||||
return data
|
||||
except Exception as e:
|
||||
print(f"数据源 {source.type} 失败: {e}")
|
||||
continue
|
||||
|
||||
raise ValueError("所有数据源均失败")
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 8. **配置版本控制**(解决 V1 问题 #10)
|
||||
|
||||
```yaml
|
||||
# ❌ V1: 无版本信息
|
||||
# ETF轮动策略配置
|
||||
# (无版本)
|
||||
|
||||
# ✅ V2: 元数据
|
||||
metadata:
|
||||
version: "1.0.0"
|
||||
strategy: "rotation"
|
||||
description: "ETF轮动策略 V2 - 基于 framework_v2 架构"
|
||||
last_updated: "2024-04-16"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Schema 层次结构
|
||||
|
||||
```
|
||||
RotationStrategyConfig
|
||||
├── metadata: MetadataConfig
|
||||
│ ├── version: str
|
||||
│ ├── strategy: str
|
||||
│ ├── description: str
|
||||
│ └── last_updated: str
|
||||
│
|
||||
├── asset_pools: AssetPool
|
||||
│ ├── equity: Dict[str, AssetConfig]
|
||||
│ ├── commodity: Dict[str, AssetConfig]
|
||||
│ └── fixed_income: Dict[str, AssetConfig]
|
||||
│
|
||||
├── benchmark: BenchmarkConfig
|
||||
│ ├── code: str
|
||||
│ └── name: str
|
||||
│
|
||||
├── backtest: BacktestConfig
|
||||
│ ├── start_date: str
|
||||
│ └── end_date: Optional[str]
|
||||
│
|
||||
├── factor: FactorConfig
|
||||
│ ├── type: FactorType
|
||||
│ ├── n_days: int (5-250)
|
||||
│ ├── auto_day: bool
|
||||
│ ├── min_days: int
|
||||
│ └── max_days: int
|
||||
│
|
||||
├── rotation: RotationConfig
|
||||
│ ├── select_num: int (1-10)
|
||||
│ ├── diversified: bool
|
||||
│ └── threshold: ThresholdConfig
|
||||
│ ├── mode: ThresholdMode
|
||||
│ ├── fixed_value: float
|
||||
│ └── dynamic: DynamicThresholdConfig
|
||||
│ ├── reference: str
|
||||
│ ├── ratio: float
|
||||
│ ├── fallback_enabled: bool
|
||||
│ └── fallback_value: float
|
||||
│
|
||||
├── rebalance: RebalanceConfig
|
||||
│ ├── min_hold_days: int (1-30)
|
||||
│ ├── score_threshold: float (0-0.5)
|
||||
│ └── trade_cost: float (0-0.01)
|
||||
│
|
||||
├── premium_control: PremiumControlConfig
|
||||
│ ├── enabled: bool
|
||||
│ ├── default_threshold: float
|
||||
│ ├── mode: PremiumMode
|
||||
│ ├── penalty_factor: float
|
||||
│ └── market_overrides: Dict[str, MarketPremiumOverride]
|
||||
│
|
||||
└── data: DataConfig
|
||||
├── sources: List[DataSourceConfig]
|
||||
├── use_cache: bool
|
||||
└── cache_dir: str
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 使用示例
|
||||
|
||||
### 基础使用
|
||||
|
||||
```python
|
||||
from framework_v2.config import load_config
|
||||
|
||||
# 加载配置文件
|
||||
config = load_config('rotation_example.yaml')
|
||||
|
||||
# 访问配置
|
||||
print(f"动量窗口: {config.factor.n_days}")
|
||||
print(f"选股数量: {config.rotation.select_num}")
|
||||
print(f"数据源: {len(config.data.sources)} 个")
|
||||
```
|
||||
|
||||
### 验证错误处理
|
||||
|
||||
```python
|
||||
from pydantic import ValidationError
|
||||
|
||||
try:
|
||||
config = load_config('invalid_config.yaml')
|
||||
except ValidationError as e:
|
||||
print(f"配置验证失败: {e}")
|
||||
# 输出详细错误信息
|
||||
for error in e.errors():
|
||||
print(f" - {error['loc']}: {error['msg']}")
|
||||
```
|
||||
|
||||
### 环境变量
|
||||
|
||||
```bash
|
||||
# 设置环境变量
|
||||
export FLASK_API_URL="https://k3s.tokenpluse.xyz"
|
||||
export TUSHARE_TOKEN="your_token_here"
|
||||
|
||||
# 加载配置(自动替换环境变量)
|
||||
config = load_config('rotation_example.yaml')
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 文件结构
|
||||
|
||||
```
|
||||
framework_v2/config/
|
||||
├── __init__.py # 导出模块
|
||||
├── schemas.py # Pydantic Schema 定义(275 行)
|
||||
├── loader.py # 配置加载器(237 行)
|
||||
├── rotation_example.yaml # 示例配置文件(195 行)
|
||||
└── CONFIG_DESIGN.md # 配置设计文档(本文件)
|
||||
|
||||
framework_v2/tests/
|
||||
└── test_config.py # 配置测试(286 行)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 测试验证
|
||||
|
||||
### 测试结果
|
||||
|
||||
```
|
||||
✓ 测试 1: 加载配置文件 - 通过
|
||||
✓ 测试 2: 资产池配置 - 通过
|
||||
✓ 测试 3: 阈值配置 - 通过
|
||||
✓ 测试 4: 数据源配置 - 通过
|
||||
✓ 测试 5: 验证错误处理 - 通过
|
||||
✓ 测试 6: 环境变量替换 - 通过
|
||||
|
||||
总计: 6/6 通过
|
||||
```
|
||||
|
||||
### 验证覆盖
|
||||
|
||||
| 验证项 | 测试内容 | 状态 |
|
||||
|--------|----------|------|
|
||||
| 配置加载 | YAML 解析 + 环境变量替换 | ✅ |
|
||||
| 类型验证 | n_days 范围、必需字段 | ✅ |
|
||||
| 资产池 | 股票/商品/债券分类 | ✅ |
|
||||
| 阈值配置 | 固定/动态模式切换 | ✅ |
|
||||
| 数据源 | 多源降级配置 | ✅ |
|
||||
| 错误处理 | ValidationError 捕获 | ✅ |
|
||||
|
||||
---
|
||||
|
||||
## V1 vs V2 对比
|
||||
|
||||
| 特性 | V1 | V2 | 改进 |
|
||||
|------|----|----|----|
|
||||
| **类型安全** | ❌ 无验证 | ✅ Pydantic Schema | 早期失败 |
|
||||
| **敏感信息** | ❌ 硬编码 | ✅ 环境变量 | 安全性 |
|
||||
| **资产分类** | ❌ 混合 | ✅ 按类别分组 | 可维护性 |
|
||||
| **注释** | ❌ 冗长(30行) | ✅ 精简 + 独立文档 | 可读性 |
|
||||
| **阈值逻辑** | ❌ V2/V3 共存 | ✅ 统一配置 | 逻辑清晰 |
|
||||
| **市场类型** | ❌ 随意字符串 | ✅ 标准枚举 | 一致性 |
|
||||
| **数据源** | ❌ 扁平化 | ✅ 优先级列表 | 可靠性 |
|
||||
| **版本控制** | ❌ 无 | ✅ 元数据 | 可追溯 |
|
||||
|
||||
---
|
||||
|
||||
## 迁移指南
|
||||
|
||||
### 从 V1 迁移到 V2
|
||||
|
||||
#### 1. 更新配置文件结构
|
||||
|
||||
```yaml
|
||||
# V1
|
||||
code_list:
|
||||
"399006.SZ":
|
||||
name: "创业板指"
|
||||
etf: "159915.SZ"
|
||||
market: "A"
|
||||
|
||||
# V2
|
||||
asset_pools:
|
||||
equity:
|
||||
"399006.SZ":
|
||||
name: "创业板指"
|
||||
etf: "159915.SZ"
|
||||
market: "CN_EQUITY"
|
||||
```
|
||||
|
||||
#### 2. 更新市场类型
|
||||
|
||||
```yaml
|
||||
# V1 → V2 映射
|
||||
"A" → "CN_EQUITY"
|
||||
"US" → "US_EQUITY"
|
||||
"HK" → "HK_EQUITY"
|
||||
"COMMODITY" → "COMMODITY"
|
||||
"BOND" → "FIXED_INCOME"
|
||||
```
|
||||
|
||||
#### 3. 更新阈值配置
|
||||
|
||||
```yaml
|
||||
# V1
|
||||
min_score: 0.0
|
||||
bond_threshold:
|
||||
enabled: true
|
||||
bond_code: "931862.CSI"
|
||||
ratio: 1.0
|
||||
|
||||
# V2
|
||||
rotation:
|
||||
threshold:
|
||||
mode: "dynamic"
|
||||
dynamic:
|
||||
reference: "931862.CSI"
|
||||
ratio: 1.0
|
||||
```
|
||||
|
||||
#### 4. 更新数据源配置
|
||||
|
||||
```yaml
|
||||
# V1
|
||||
flask_api:
|
||||
enabled: true
|
||||
url: "https://k3s.tokenpluse.xyz"
|
||||
|
||||
# V2
|
||||
data:
|
||||
sources:
|
||||
- type: "flask_api"
|
||||
enabled: true
|
||||
url: "${FLASK_API_URL}"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 最佳实践
|
||||
|
||||
### 1. 使用环境变量管理敏感信息
|
||||
|
||||
```bash
|
||||
# .env 文件(不要提交到 Git)
|
||||
FLASK_API_URL=https://k3s.tokenpluse.xyz
|
||||
TUSHARE_TOKEN=your_token_here
|
||||
SSH_HOST=8.218.167.69
|
||||
SSH_KEY_PATH=/path/to/hk_ecs.pem
|
||||
```
|
||||
|
||||
### 2. 为不同环境创建不同配置
|
||||
|
||||
```
|
||||
config/
|
||||
├── rotation_dev.yaml # 开发环境
|
||||
├── rotation_prod.yaml # 生产环境
|
||||
└── rotation_test.yaml # 测试环境
|
||||
```
|
||||
|
||||
### 3. 使用版本控制追踪配置变更
|
||||
|
||||
```yaml
|
||||
metadata:
|
||||
version: "1.0.0"
|
||||
last_updated: "2024-04-16"
|
||||
changelog:
|
||||
- "2024-04-16: 初始版本"
|
||||
```
|
||||
|
||||
### 4. 定期验证配置
|
||||
|
||||
```bash
|
||||
# 运行配置测试
|
||||
python framework_v2/tests/test_config.py
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 未来优化
|
||||
|
||||
1. [ ] 配置热重载(无需重启策略)
|
||||
2. [ ] 配置 diff 工具(对比版本差异)
|
||||
3. [ ] 配置 UI 编辑器(可视化配置)
|
||||
4. [ ] 配置模板系统(快速创建新策略)
|
||||
|
||||
---
|
||||
|
||||
## 版本历史
|
||||
|
||||
- **2024-04-16**: 初始版本
|
||||
- Pydantic Schema 验证
|
||||
- 环境变量替换
|
||||
- 资产池分类
|
||||
- 统一阈值配置
|
||||
- 多数据源降级
|
||||
- 6/6 测试通过
|
||||
72
archive/framework_v2/config/__init__.py
Normal file
72
archive/framework_v2/config/__init__.py
Normal file
@@ -0,0 +1,72 @@
|
||||
"""
|
||||
配置模块
|
||||
|
||||
提供配置加载、验证、管理功能
|
||||
"""
|
||||
|
||||
from framework_v2.config.schemas import (
|
||||
# 完整配置
|
||||
RotationStrategyConfig,
|
||||
StrategyConfig, # 通用配置
|
||||
|
||||
# 子配置
|
||||
AssetPool,
|
||||
AssetConfig,
|
||||
PremiumConfig,
|
||||
GroupConfig,
|
||||
FactorConfig,
|
||||
RotationConfig,
|
||||
ThresholdConfig,
|
||||
DynamicThresholdConfig,
|
||||
RebalanceConfig,
|
||||
PremiumControlConfig,
|
||||
DataConfig,
|
||||
DataSourceConfig,
|
||||
BenchmarkConfig,
|
||||
BacktestConfig,
|
||||
MetadataConfig,
|
||||
|
||||
# 枚举(已移除 MarketType,改用字符串 group)
|
||||
FactorType,
|
||||
PremiumMode,
|
||||
ThresholdMode,
|
||||
DataSourceType,
|
||||
)
|
||||
|
||||
from framework_v2.config.loader import (
|
||||
ConfigLoader,
|
||||
get_config_loader,
|
||||
load_config,
|
||||
)
|
||||
|
||||
__all__ = [
|
||||
# 配置 Schema
|
||||
'RotationStrategyConfig',
|
||||
'StrategyConfig',
|
||||
'AssetPool',
|
||||
'AssetConfig',
|
||||
'PremiumConfig',
|
||||
'GroupConfig',
|
||||
'FactorConfig',
|
||||
'RotationConfig',
|
||||
'ThresholdConfig',
|
||||
'DynamicThresholdConfig',
|
||||
'RebalanceConfig',
|
||||
'PremiumControlConfig',
|
||||
'DataConfig',
|
||||
'DataSourceConfig',
|
||||
'BenchmarkConfig',
|
||||
'BacktestConfig',
|
||||
'MetadataConfig',
|
||||
|
||||
# 枚举(已移除 MarketType,改用字符串 group)
|
||||
'FactorType',
|
||||
'PremiumMode',
|
||||
'ThresholdMode',
|
||||
'DataSourceType',
|
||||
|
||||
# 加载器
|
||||
'ConfigLoader',
|
||||
'get_config_loader',
|
||||
'load_config',
|
||||
]
|
||||
247
archive/framework_v2/config/loader.py
Normal file
247
archive/framework_v2/config/loader.py
Normal file
@@ -0,0 +1,247 @@
|
||||
"""
|
||||
配置加载器
|
||||
|
||||
支持:
|
||||
1. YAML 配置文件加载
|
||||
2. Pydantic Schema 验证
|
||||
3. 环境变量替换
|
||||
4. 配置合并(默认值 + 用户配置)
|
||||
"""
|
||||
|
||||
import os
|
||||
import re
|
||||
import yaml
|
||||
from pathlib import Path
|
||||
from typing import Optional, Dict, Any
|
||||
|
||||
from framework_v2.config.schemas import StrategyConfig, RotationStrategyConfig
|
||||
|
||||
|
||||
class ConfigLoader:
|
||||
"""
|
||||
配置加载器
|
||||
|
||||
用法:
|
||||
loader = ConfigLoader()
|
||||
config = loader.load('config/rotation.yaml')
|
||||
"""
|
||||
|
||||
def __init__(self, config_dir: str = None):
|
||||
"""
|
||||
初始化
|
||||
|
||||
Args:
|
||||
config_dir: 配置目录(默认 framework_v2/config)
|
||||
"""
|
||||
if config_dir is None:
|
||||
# 默认配置目录
|
||||
config_dir = Path(__file__).parent
|
||||
|
||||
self.config_dir = Path(config_dir)
|
||||
|
||||
def load(self, config_file: str, config_type: str = 'strategy') -> StrategyConfig:
|
||||
"""
|
||||
加载配置文件
|
||||
|
||||
Args:
|
||||
config_file: 配置文件路径(相对路径或绝对路径)
|
||||
config_type: 配置类型('strategy' 或 'rotation')
|
||||
|
||||
Returns:
|
||||
验证后的配置对象
|
||||
|
||||
示例:
|
||||
>>> loader = ConfigLoader()
|
||||
>>> config = loader.load('rotation_example.yaml')
|
||||
>>> print(config.factor.n_days)
|
||||
25
|
||||
"""
|
||||
# 1. 解析文件路径
|
||||
config_path = self._resolve_path(config_file)
|
||||
|
||||
# 2. 读取 YAML
|
||||
with open(config_path, 'r', encoding='utf-8') as f:
|
||||
config_dict = yaml.safe_load(f)
|
||||
|
||||
# 3. 环境变量替换
|
||||
config_dict = self._substitute_env_vars(config_dict)
|
||||
|
||||
# 4. Pydantic 验证(根据类型选择 Schema)
|
||||
if config_type == 'rotation':
|
||||
# 兼容旧版本:轮动策略专用配置
|
||||
config = RotationStrategyConfig(**config_dict)
|
||||
else:
|
||||
# 通用策略配置(推荐)
|
||||
config = StrategyConfig(**config_dict)
|
||||
|
||||
return config
|
||||
|
||||
def load_dict(self, config_dict: Dict[str, Any], config_type: str = 'strategy') -> StrategyConfig:
|
||||
"""
|
||||
从字典加载配置
|
||||
|
||||
Args:
|
||||
config_dict: 配置字典
|
||||
config_type: 配置类型('strategy' 或 'rotation')
|
||||
|
||||
Returns:
|
||||
验证后的配置对象
|
||||
"""
|
||||
# 环境变量替换
|
||||
config_dict = self._substitute_env_vars(config_dict)
|
||||
|
||||
# Pydantic 验证(根据类型选择 Schema)
|
||||
if config_type == 'rotation':
|
||||
config = RotationStrategyConfig(**config_dict)
|
||||
else:
|
||||
config = StrategyConfig(**config_dict)
|
||||
|
||||
return config
|
||||
|
||||
def _resolve_path(self, config_file: str) -> Path:
|
||||
"""
|
||||
解析配置文件路径
|
||||
|
||||
Args:
|
||||
config_file: 配置文件路径
|
||||
|
||||
Returns:
|
||||
绝对路径
|
||||
"""
|
||||
path = Path(config_file)
|
||||
|
||||
# 如果是绝对路径,直接返回
|
||||
if path.is_absolute():
|
||||
if not path.exists():
|
||||
raise FileNotFoundError(f"配置文件不存在: {path}")
|
||||
return path
|
||||
|
||||
# 相对路径:先在配置目录查找
|
||||
config_path = self.config_dir / path
|
||||
if config_path.exists():
|
||||
return config_path
|
||||
|
||||
# 然后在当前工作目录查找
|
||||
cwd_path = Path.cwd() / path
|
||||
if cwd_path.exists():
|
||||
return cwd_path
|
||||
|
||||
raise FileNotFoundError(
|
||||
f"配置文件未找到: {path}\n"
|
||||
f"搜索路径:\n"
|
||||
f" - {config_path}\n"
|
||||
f" - {cwd_path}"
|
||||
)
|
||||
|
||||
def _substitute_env_vars(self, config: Any) -> Any:
|
||||
"""
|
||||
替换配置中的环境变量
|
||||
|
||||
支持格式:
|
||||
- ${VAR_NAME}
|
||||
- ${VAR_NAME:default_value}
|
||||
|
||||
Args:
|
||||
config: 配置对象(dict/list/str)
|
||||
|
||||
Returns:
|
||||
替换后的配置
|
||||
"""
|
||||
if isinstance(config, dict):
|
||||
return {
|
||||
key: self._substitute_env_vars(value)
|
||||
for key, value in config.items()
|
||||
}
|
||||
elif isinstance(config, list):
|
||||
return [
|
||||
self._substitute_env_vars(item)
|
||||
for item in config
|
||||
]
|
||||
elif isinstance(config, str):
|
||||
# 匹配 ${VAR_NAME} 或 ${VAR_NAME:default}
|
||||
pattern = r'\$\{([^}]+)\}'
|
||||
|
||||
def replace_match(match):
|
||||
var_expr = match.group(1)
|
||||
|
||||
# 检查是否有默认值
|
||||
if ':' in var_expr:
|
||||
var_name, default = var_expr.split(':', 1)
|
||||
else:
|
||||
var_name = var_expr
|
||||
default = None
|
||||
|
||||
# 从环境变量读取
|
||||
value = os.getenv(var_name)
|
||||
|
||||
if value is None:
|
||||
if default is not None:
|
||||
return default
|
||||
else:
|
||||
raise ValueError(
|
||||
f"环境变量未设置: {var_name}\n"
|
||||
f"请设置环境变量或在配置中使用默认值: ${{{var_name}:default_value}}"
|
||||
)
|
||||
|
||||
return value
|
||||
|
||||
return re.sub(pattern, replace_match, config)
|
||||
else:
|
||||
return config
|
||||
|
||||
def get_available_configs(self) -> list:
|
||||
"""
|
||||
获取可用的配置文件列表
|
||||
|
||||
Returns:
|
||||
配置文件名列表
|
||||
"""
|
||||
if not self.config_dir.exists():
|
||||
return []
|
||||
|
||||
return [
|
||||
f.name
|
||||
for f in self.config_dir.glob('*.yaml')
|
||||
if f.is_file()
|
||||
]
|
||||
|
||||
|
||||
# 全局实例
|
||||
_config_loader: Optional[ConfigLoader] = None
|
||||
|
||||
|
||||
def get_config_loader(config_dir: str = None) -> ConfigLoader:
|
||||
"""
|
||||
获取配置加载器单例
|
||||
|
||||
Args:
|
||||
config_dir: 配置目录
|
||||
|
||||
Returns:
|
||||
ConfigLoader 实例
|
||||
"""
|
||||
global _config_loader
|
||||
|
||||
if _config_loader is None:
|
||||
_config_loader = ConfigLoader(config_dir)
|
||||
|
||||
return _config_loader
|
||||
|
||||
|
||||
def load_config(config_file: str, config_type: str = 'strategy') -> StrategyConfig:
|
||||
"""
|
||||
快捷函数:加载配置文件
|
||||
|
||||
Args:
|
||||
config_file: 配置文件路径
|
||||
config_type: 配置类型('strategy' 或 'rotation')
|
||||
|
||||
Returns:
|
||||
验证后的配置对象
|
||||
|
||||
示例:
|
||||
>>> from framework_v2.config import load_config
|
||||
>>> config = load_config('rotation_example.yaml')
|
||||
"""
|
||||
loader = get_config_loader()
|
||||
return loader.load(config_file, config_type=config_type)
|
||||
268
archive/framework_v2/config/rotation_global.yaml
Normal file
268
archive/framework_v2/config/rotation_global.yaml
Normal file
@@ -0,0 +1,268 @@
|
||||
# 跨市场轮动策略配置(扁平化设计)
|
||||
#
|
||||
# 配置版本: 2.0.0
|
||||
# 最后更新: 2024-04-16
|
||||
# 策略名称: rotation_global
|
||||
# 描述: 全球资产大类轮动 - 扁平化资产池设计
|
||||
|
||||
# ============================================================
|
||||
# 元数据
|
||||
# ============================================================
|
||||
metadata:
|
||||
version: "2.0.0"
|
||||
strategy: "rotation_global"
|
||||
description: "全球资产大类轮动策略 V2 - 扁平化资产池"
|
||||
last_updated: "2024-04-16"
|
||||
|
||||
# ============================================================
|
||||
# 资产池配置(扁平化设计)
|
||||
# ============================================================
|
||||
asset_pools:
|
||||
assets:
|
||||
# ============================================================
|
||||
# 美股指数(通过 A 股 ETF 交易)
|
||||
# ============================================================
|
||||
"NDX":
|
||||
name: "纳指100"
|
||||
group: "US_TECH"
|
||||
signal_source: "NDX" # 纳指信号
|
||||
trade_source: "513100.SH" # A股ETF交易
|
||||
description: "纳斯达克100指数,科技股代表"
|
||||
|
||||
"SPX":
|
||||
name: "标普500"
|
||||
group: "US_TECH"
|
||||
signal_source: "SPX"
|
||||
trade_source: "513500.SH"
|
||||
description: "标普500指数,美股大盘"
|
||||
|
||||
# ============================================================
|
||||
# A股指数(直接交易 ETF)
|
||||
# ============================================================
|
||||
"399006.SZ":
|
||||
name: "创业板指"
|
||||
group: "CN_GROWTH"
|
||||
signal_source: "399006.SZ"
|
||||
trade_source: "159915.SZ"
|
||||
description: "创业板指数,成长股代表"
|
||||
|
||||
"000300.SH":
|
||||
name: "沪深300"
|
||||
group: "CN_GROWTH"
|
||||
signal_source: "000300.SH"
|
||||
trade_source: "510300.SH"
|
||||
description: "沪深300指数,大盘蓝筹"
|
||||
|
||||
"H30269.CSI":
|
||||
name: "中证红利低波"
|
||||
group: "CN_GROWTH"
|
||||
signal_source: "H30269.CSI"
|
||||
trade_source: "512890.SH"
|
||||
description: "红利低波指数,价值股代表"
|
||||
|
||||
# ============================================================
|
||||
# 日本股市(通过 A 股 ETF 交易)
|
||||
# ============================================================
|
||||
"N225":
|
||||
name: "日经225"
|
||||
group: "JP_BROAD"
|
||||
signal_source: "N225"
|
||||
trade_source: "513520.SH"
|
||||
description: "日经225指数,日本股市"
|
||||
|
||||
# ============================================================
|
||||
# 欧洲股市(通过 A 股 ETF 交易)
|
||||
# ============================================================
|
||||
"GDAXI":
|
||||
name: "德国DAX"
|
||||
group: "EU_BROAD"
|
||||
signal_source: "GDAXI"
|
||||
trade_source: "513030.SH"
|
||||
description: "德国DAX指数,欧洲股市"
|
||||
|
||||
# ============================================================
|
||||
# 港股(通过 A 股 ETF 交易)
|
||||
# ============================================================
|
||||
"HSI":
|
||||
name: "恒生指数"
|
||||
group: "HK_TECH"
|
||||
signal_source: "HSI"
|
||||
trade_source: "159920.SZ"
|
||||
description: "恒生指数,香港股市"
|
||||
|
||||
"HSTECH.HK":
|
||||
name: "恒生科技"
|
||||
group: "HK_TECH"
|
||||
signal_source: "HSTECH.HK"
|
||||
trade_source: "513130.SH"
|
||||
description: "恒生科技指数,港股科技"
|
||||
|
||||
# ============================================================
|
||||
# 商品(国际期货信号 → A股ETF交易)
|
||||
# ============================================================
|
||||
"GC=F":
|
||||
name: "黄金"
|
||||
group: "COMMODITY"
|
||||
signal_source: "GC=F" # COMEX黄金期货
|
||||
trade_source: "518880.SH" # A股黄金ETF
|
||||
description: "COMEX黄金期货,避险资产"
|
||||
|
||||
"CL=F":
|
||||
name: "原油"
|
||||
group: "COMMODITY"
|
||||
signal_source: "CL=F" # WTI原油期货
|
||||
trade_source: "160723.SZ" # A股原油基金
|
||||
description: "WTI原油期货,能源商品"
|
||||
|
||||
"HG=F":
|
||||
name: "有色金属"
|
||||
group: "COMMODITY"
|
||||
signal_source: "HG=F" # COMEX铜期货
|
||||
trade_source: "159980.SZ" # A股有色ETF
|
||||
description: "COMEX铜期货,工业金属"
|
||||
|
||||
# ============================================================
|
||||
# 固定收益(直接交易指数)
|
||||
# ============================================================
|
||||
"931862.CSI":
|
||||
name: "短债指数"
|
||||
group: "FIXED_INCOME"
|
||||
signal_source: "931862.CSI"
|
||||
trade_source: "931862.CSI" # 直接交易指数(无ETF)
|
||||
description: "中证0-9个月国债指数,久期<1年,防御配置"
|
||||
|
||||
# ============================================================
|
||||
# 加密货币(未来扩展示例)
|
||||
# ============================================================
|
||||
# "BTC":
|
||||
# name: "比特币"
|
||||
# group: "CRYPTO"
|
||||
# signal_source: "BTC"
|
||||
# trade_source: "BTC"
|
||||
# description: "比特币,数字黄金"
|
||||
|
||||
# ============================================================
|
||||
# 外汇(未来扩展示例)
|
||||
# ============================================================
|
||||
# "EURUSD":
|
||||
# name: "欧元/美元"
|
||||
# group: "FOREX"
|
||||
# signal_source: "EURUSD"
|
||||
# trade_source: "EURUSD"
|
||||
# description: "欧元/美元汇率"
|
||||
|
||||
# ============================================================
|
||||
# 基准配置
|
||||
# ============================================================
|
||||
benchmark:
|
||||
code: "000300.SH"
|
||||
name: "沪深300"
|
||||
|
||||
# ============================================================
|
||||
# 回测配置
|
||||
# ============================================================
|
||||
backtest:
|
||||
start_date: "2020-01-01"
|
||||
# end_date: null # null 表示至今
|
||||
|
||||
# ============================================================
|
||||
# 因子配置
|
||||
# ============================================================
|
||||
factor:
|
||||
type: "weighted_momentum" # 因子类型: momentum / slope_r2 / weighted_momentum
|
||||
n_days: 25 # 动量窗口期(5-250天)
|
||||
|
||||
# 动态周期参数(可选)
|
||||
auto_day: false # 是否启用动态周期
|
||||
min_days: 20 # 最小周期
|
||||
max_days: 60 # 最大周期
|
||||
|
||||
# ============================================================
|
||||
# 轮动配置
|
||||
# ============================================================
|
||||
rotation:
|
||||
# ============================================================
|
||||
# 模式 1:全局选股(默认)
|
||||
# ============================================================
|
||||
select_num: 5 # 全局选 Top-5
|
||||
diversified: false # 不分散化
|
||||
|
||||
# ============================================================
|
||||
# 模式 2:分散化选股(取消注释启用)
|
||||
# ============================================================
|
||||
# diversified: true # 启用分散化
|
||||
# diversification_groups: # 按市场分组选股
|
||||
# - group: "US_TECH"
|
||||
# select_num: 1 # 美股选 1 只
|
||||
# - group: "CN_GROWTH"
|
||||
# select_num: 1 # A股选 1 只
|
||||
# - group: "JP_BROAD"
|
||||
# select_num: 1 # 日本选 1 只
|
||||
# - group: "EU_BROAD"
|
||||
# select_num: 1 # 欧洲选 1 只
|
||||
# - group: "HK_TECH"
|
||||
# select_num: 1 # 港股选 1 只
|
||||
# - group: "COMMODITY"
|
||||
# select_num: 1 # 商品选 1 只
|
||||
# - group: "FIXED_INCOME"
|
||||
# select_num: 1 # 债券选 1 只
|
||||
|
||||
# 阈值配置(统一 V2/V3)
|
||||
threshold:
|
||||
mode: "dynamic" # 阈值模式: fixed / dynamic
|
||||
fixed_value: 0.0 # 固定阈值(mode=fixed时使用)
|
||||
|
||||
# 动态阈值配置(mode=dynamic时使用)
|
||||
dynamic:
|
||||
reference: "931862.CSI" # 参考标的(短债指数)
|
||||
ratio: 1.0 # 阈值 = 短债动量 × ratio
|
||||
fallback_enabled: true # 参考不可用时是否回退
|
||||
fallback_value: 0.0 # 回退值
|
||||
|
||||
# ============================================================
|
||||
# 调仓配置
|
||||
# ============================================================
|
||||
rebalance:
|
||||
min_hold_days: 1 # 最低持有天数(1-30)
|
||||
score_threshold: 0.0 # 调仓得分阈值(0-0.5,表示%)
|
||||
trade_cost: 0.001 # 单次换仓成本(0-0.01,即 0.1%)
|
||||
|
||||
# ============================================================
|
||||
# 溢价控制配置
|
||||
# ============================================================
|
||||
premium_control:
|
||||
enabled: true # 是否启用溢价控制
|
||||
default_threshold: 0.10 # 默认溢价阈值(10%)
|
||||
mode: "filter" # 控制模式: filter(排除)/ penalize(降权)
|
||||
penalty_factor: 0.5 # 降权惩罚系数
|
||||
|
||||
# 按市场覆盖配置
|
||||
market_overrides:
|
||||
CN_EQUITY: # A股 ETF
|
||||
enabled: false # 不启用(溢价通常 < 0.5%)
|
||||
HK_EQUITY: # 港股 ETF
|
||||
enabled: true
|
||||
threshold: 0.10 # 阈值 10%
|
||||
US_EQUITY: # 美股 ETF
|
||||
enabled: true
|
||||
threshold: 0.10 # 阈值 10%
|
||||
JP_EQUITY: # 日本 ETF
|
||||
enabled: true
|
||||
threshold: 0.10 # 阈值 10%
|
||||
EU_EQUITY: # 欧洲 ETF
|
||||
enabled: true
|
||||
threshold: 0.10 # 阈值 10%
|
||||
COMMODITY: # 商品 ETF
|
||||
enabled: false # 不启用
|
||||
|
||||
# ============================================================
|
||||
# 数据配置
|
||||
# ============================================================
|
||||
data:
|
||||
# 数据源列表(按优先级排序)
|
||||
sources:
|
||||
# 主数据源:Flask API
|
||||
- type: "flask_api"
|
||||
enabled: true
|
||||
url: "${FLASK_API_URL}" # 从环境变量读取
|
||||
timeout: 120
|
||||
444
archive/framework_v2/config/schemas.py
Normal file
444
archive/framework_v2/config/schemas.py
Normal file
@@ -0,0 +1,444 @@
|
||||
"""
|
||||
配置 Schema 定义
|
||||
|
||||
使用 Pydantic 验证配置文件的类型安全
|
||||
"""
|
||||
|
||||
from pydantic import BaseModel, Field, field_validator, model_validator
|
||||
from typing import Optional, Dict, List, Literal
|
||||
from enum import Enum
|
||||
from datetime import date
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 枚举类型
|
||||
# ============================================================
|
||||
|
||||
# 注意:不再使用 MarketType 枚举,改用字符串类型的 group 字段
|
||||
# group 字段用于策略分组(组内竞争,强制分散)
|
||||
|
||||
|
||||
class FactorType(str, Enum):
|
||||
"""因子类型枚举"""
|
||||
MOMENTUM = "momentum"
|
||||
SLOPE_R2 = "slope_r2"
|
||||
WEIGHTED_MOMENTUM = "weighted_momentum"
|
||||
|
||||
|
||||
class PremiumMode(str, Enum):
|
||||
"""溢价控制模式"""
|
||||
FILTER = "filter" # 完全排除
|
||||
PENALIZE = "penalize" # 降权
|
||||
|
||||
|
||||
class ThresholdMode(str, Enum):
|
||||
"""阈值模式"""
|
||||
FIXED = "fixed" # 固定阈值
|
||||
DYNAMIC = "dynamic" # 动态阈值
|
||||
|
||||
|
||||
class DataSourceType(str, Enum):
|
||||
"""数据源类型"""
|
||||
FLASK_API = "flask_api"
|
||||
TUSHARE = "tushare"
|
||||
YFINANCE = "yfinance"
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 资产池 Schema(扁平化设计)
|
||||
# ============================================================
|
||||
|
||||
class PremiumConfig(BaseModel):
|
||||
"""溢价控制配置"""
|
||||
enabled: bool = Field(default=True, description="是否启用")
|
||||
threshold: float = Field(default=0.10, ge=0, le=1.0, description="溢价阈值")
|
||||
|
||||
|
||||
class AssetConfig(BaseModel):
|
||||
"""
|
||||
标的配置(通用,支持所有场景)
|
||||
|
||||
场景 1:指数信号 → 指数收益
|
||||
signal_source: "NDX"
|
||||
trade_source: "NDX"
|
||||
|
||||
场景 2:指数信号 → ETF收益
|
||||
signal_source: "NDX"
|
||||
trade_source: "513100.SH"
|
||||
|
||||
场景 3:ETF信号 → ETF收益
|
||||
signal_source: "518880.SH"
|
||||
trade_source: "518880.SH"
|
||||
|
||||
场景 4:个股信号 → 个股收益
|
||||
signal_source: "AAPL"
|
||||
trade_source: "AAPL"
|
||||
"""
|
||||
name: str = Field(..., description="标的名称")
|
||||
group: str = Field(..., description="策略分组(组内竞争,强制分散)")
|
||||
|
||||
# 核心字段:信号来源和交易来源
|
||||
signal_source: str = Field(..., description="信号来源代码(计算因子用)")
|
||||
trade_source: str = Field(..., description="交易来源代码(计算收益用)")
|
||||
|
||||
# 可选字段
|
||||
description: Optional[str] = Field(None, description="标的描述")
|
||||
etf: Optional[str] = Field(None, description="ETF代码(兼容旧配置)")
|
||||
premium_control: Optional["PremiumConfig"] = Field(None, description="溢价控制配置")
|
||||
|
||||
@property
|
||||
def is_cross_market(self) -> bool:
|
||||
"""是否跨市场(信号和交易不同)"""
|
||||
return self.signal_source != self.trade_source
|
||||
|
||||
|
||||
class AssetPool(BaseModel):
|
||||
"""
|
||||
资产池(扁平化设计)
|
||||
|
||||
优势:
|
||||
1. 不预设分类,支持任意策略分组
|
||||
2. 通过 group 字段自动分组
|
||||
3. 配置简单直观
|
||||
4. 易于扩展新分组
|
||||
|
||||
示例:
|
||||
asset_pool:
|
||||
assets:
|
||||
"NDX":
|
||||
name: "纳指100"
|
||||
group: "US_TECH"
|
||||
signal_source: "NDX"
|
||||
trade_source: "513100.SH"
|
||||
|
||||
"BTC":
|
||||
name: "比特币"
|
||||
group: "CRYPTO"
|
||||
signal_source: "BTC"
|
||||
trade_source: "BTC"
|
||||
"""
|
||||
assets: Dict[str, AssetConfig] = Field(
|
||||
default_factory=dict,
|
||||
description="所有标的(flat结构)"
|
||||
)
|
||||
|
||||
@property
|
||||
def by_group(self) -> Dict[str, Dict[str, AssetConfig]]:
|
||||
"""按策略分组"""
|
||||
groups = {}
|
||||
for code, asset in self.assets.items():
|
||||
group = asset.group
|
||||
if group not in groups:
|
||||
groups[group] = {}
|
||||
groups[group][code] = asset
|
||||
return groups
|
||||
|
||||
@property
|
||||
def groups(self) -> list:
|
||||
"""获取所有策略分组"""
|
||||
return list(self.by_group.keys())
|
||||
|
||||
def get_signal_codes(self, group: str = None) -> list:
|
||||
"""
|
||||
获取信号标的
|
||||
|
||||
Args:
|
||||
group: 可选,过滤特定分组(如 'US_TECH')
|
||||
"""
|
||||
if group:
|
||||
return [
|
||||
asset.signal_source
|
||||
for asset in self.assets.values()
|
||||
if asset.group == group
|
||||
]
|
||||
return [asset.signal_source for asset in self.assets.values()]
|
||||
|
||||
def get_trade_codes(self, group: str = None) -> list:
|
||||
"""获取交易标的"""
|
||||
if group:
|
||||
return [
|
||||
asset.trade_source
|
||||
for asset in self.assets.values()
|
||||
if asset.group == group
|
||||
]
|
||||
return [asset.trade_source for asset in self.assets.values()]
|
||||
|
||||
def get_signal_to_trade_mapping(self, group: str = None) -> Dict[str, str]:
|
||||
"""获取信号→交易映射"""
|
||||
mapping = {}
|
||||
for asset in self.assets.values():
|
||||
if group and asset.group != group:
|
||||
continue
|
||||
mapping[asset.signal_source] = asset.trade_source
|
||||
return mapping
|
||||
|
||||
def count(self, group: str = None) -> int:
|
||||
"""获取标的数量"""
|
||||
if group:
|
||||
return len([a for a in self.assets.values() if a.group == group])
|
||||
return len(self.assets)
|
||||
|
||||
@field_validator('assets')
|
||||
@classmethod
|
||||
def check_non_empty(cls, v):
|
||||
"""至少配置一个标的"""
|
||||
if not v:
|
||||
import warnings
|
||||
warnings.warn("资产池为空")
|
||||
return v
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 因子配置 Schema
|
||||
# ============================================================
|
||||
|
||||
class FactorConfig(BaseModel):
|
||||
"""因子配置"""
|
||||
type: FactorType = Field(default=FactorType.WEIGHTED_MOMENTUM, description="因子类型")
|
||||
n_days: int = Field(default=25, ge=5, le=250, description="动量窗口期(天数)")
|
||||
|
||||
# 动态周期参数
|
||||
auto_day: bool = Field(default=False, description="是否启用动态周期")
|
||||
min_days: int = Field(default=20, ge=5, le=100, description="最小周期")
|
||||
max_days: int = Field(default=60, ge=20, le=250, description="最大周期")
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 阈值配置 Schema
|
||||
# ============================================================
|
||||
|
||||
class DynamicThresholdConfig(BaseModel):
|
||||
"""动态阈值配置"""
|
||||
reference: str = Field(..., description="参考标的代码")
|
||||
ratio: float = Field(default=1.0, gt=0, description="倍数")
|
||||
fallback_enabled: bool = Field(default=True, description="参考不可用时是否回退")
|
||||
fallback_value: float = Field(default=0.0, description="回退值")
|
||||
|
||||
|
||||
class ThresholdConfig(BaseModel):
|
||||
"""阈值配置(统一 V2/V3)"""
|
||||
mode: ThresholdMode = Field(default=ThresholdMode.DYNAMIC, description="阈值模式")
|
||||
fixed_value: float = Field(default=0.0, description="固定阈值(mode=fixed时使用)")
|
||||
dynamic: Optional[DynamicThresholdConfig] = Field(None, description="动态阈值(mode=dynamic时使用)")
|
||||
|
||||
@model_validator(mode='after')
|
||||
def validate_dynamic_config(self):
|
||||
"""验证动态阈值配置"""
|
||||
if self.mode == ThresholdMode.DYNAMIC and self.dynamic is None:
|
||||
raise ValueError("dynamic 模式必须配置 dynamic 字段")
|
||||
return self
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 轮动配置 Schema
|
||||
# ============================================================
|
||||
|
||||
class GroupConfig(BaseModel):
|
||||
"""策略分组配置(用于分散化选股)"""
|
||||
group: str = Field(..., description="策略分组名称")
|
||||
select_num: int = Field(default=1, ge=1, le=10, description="该分组选股数量")
|
||||
|
||||
|
||||
class RotationConfig(BaseModel):
|
||||
"""
|
||||
轮动配置
|
||||
|
||||
支持两种选股模式:
|
||||
1. 全局选股:diversified=false,直接选 Top-N
|
||||
2. 分散化选股:diversified=true,按策略分组选股
|
||||
"""
|
||||
select_num: int = Field(default=3, ge=1, le=20, description="选股数量(全局模式)")
|
||||
diversified: bool = Field(default=False, description="是否分散化选股")
|
||||
|
||||
# 分散化配置(可选)
|
||||
diversification_groups: Optional[List[GroupConfig]] = Field(
|
||||
None,
|
||||
description="分散化分组配置(diversified=true时使用)"
|
||||
)
|
||||
|
||||
threshold: ThresholdConfig = Field(
|
||||
default_factory=ThresholdConfig,
|
||||
description="动量阈值"
|
||||
)
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 调仓配置 Schema
|
||||
# ============================================================
|
||||
|
||||
class RebalanceConfig(BaseModel):
|
||||
"""调仓配置"""
|
||||
min_hold_days: int = Field(default=1, ge=1, le=30, description="最低持有天数")
|
||||
score_threshold: float = Field(default=0.0, ge=0, le=0.5, description="调仓得分阈值(%)")
|
||||
trade_cost: float = Field(default=0.001, ge=0, le=0.01, description="单次换仓成本")
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 溢价控制 Schema
|
||||
# ============================================================
|
||||
|
||||
class MarketPremiumOverride(BaseModel):
|
||||
"""市场溢价覆盖配置"""
|
||||
enabled: bool = Field(default=True, description="是否启用")
|
||||
threshold: float = Field(default=0.10, ge=0, le=1.0, description="溢价阈值")
|
||||
|
||||
|
||||
class PremiumControlConfig(BaseModel):
|
||||
"""溢价控制配置"""
|
||||
enabled: bool = Field(default=True, description="是否启用溢价控制")
|
||||
default_threshold: float = Field(default=0.10, ge=0, le=1.0, description="默认溢价阈值")
|
||||
mode: PremiumMode = Field(default=PremiumMode.FILTER, description="控制模式")
|
||||
penalty_factor: float = Field(default=0.5, ge=0, le=1.0, description="降权惩罚系数")
|
||||
|
||||
# 按市场覆盖
|
||||
market_overrides: Dict[str, MarketPremiumOverride] = Field(
|
||||
default_factory=dict,
|
||||
description="按市场覆盖配置"
|
||||
)
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 数据源配置 Schema
|
||||
# ============================================================
|
||||
|
||||
class DataSourceConfig(BaseModel):
|
||||
"""单个数据源配置"""
|
||||
type: DataSourceType = Field(..., description="数据源类型")
|
||||
enabled: bool = Field(default=True, description="是否启用")
|
||||
timeout: int = Field(default=120, ge=10, le=600, description="超时时间(秒)")
|
||||
|
||||
# Flask API 特定配置
|
||||
url: Optional[str] = Field(None, description="API地址(flask_api使用)")
|
||||
|
||||
# Tushare 特定配置
|
||||
token: Optional[str] = Field(None, description="Tushare Token(tushare使用)")
|
||||
|
||||
|
||||
class DataConfig(BaseModel):
|
||||
"""数据配置"""
|
||||
sources: List[DataSourceConfig] = Field(..., description="数据源列表(按优先级排序)")
|
||||
use_cache: bool = Field(default=True, description="是否使用本地缓存")
|
||||
cache_dir: str = Field(default="data_cache", description="缓存目录")
|
||||
|
||||
@field_validator('sources')
|
||||
@classmethod
|
||||
def check_at_least_one(cls, v):
|
||||
"""至少配置一个数据源"""
|
||||
if not v:
|
||||
raise ValueError("必须配置至少一个数据源")
|
||||
return v
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 基准配置 Schema
|
||||
# ============================================================
|
||||
|
||||
class BenchmarkConfig(BaseModel):
|
||||
"""基准配置"""
|
||||
code: str = Field(..., description="基准代码")
|
||||
name: str = Field(..., description="基准名称")
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 回测配置 Schema
|
||||
# ============================================================
|
||||
|
||||
class BacktestConfig(BaseModel):
|
||||
"""回测配置"""
|
||||
start_date: str = Field(..., description="回测起始日期(YYYY-MM-DD)")
|
||||
end_date: Optional[str] = Field(None, description="回测结束日期(None表示至今)")
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 元数据 Schema
|
||||
# ============================================================
|
||||
|
||||
class MetadataConfig(BaseModel):
|
||||
"""配置元数据"""
|
||||
version: str = Field(default="1.0.0", description="配置版本")
|
||||
strategy: str = Field(default="rotation", description="策略名称")
|
||||
description: str = Field(default="", description="配置描述")
|
||||
last_updated: Optional[str] = Field(None, description="最后更新日期")
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 完整策略配置 Schema
|
||||
# ============================================================
|
||||
|
||||
class RotationStrategyConfig(BaseModel):
|
||||
"""
|
||||
ETF轮动策略完整配置
|
||||
|
||||
使用示例:
|
||||
from framework_v2.config.schemas import RotationStrategyConfig
|
||||
import yaml
|
||||
|
||||
with open('config/rotation.yaml') as f:
|
||||
config_dict = yaml.safe_load(f)
|
||||
|
||||
config = RotationStrategyConfig(**config_dict)
|
||||
"""
|
||||
metadata: MetadataConfig = Field(default_factory=MetadataConfig, description="元数据")
|
||||
|
||||
# 资产池
|
||||
asset_pools: AssetPool = Field(..., description="资产池配置")
|
||||
|
||||
# 基准
|
||||
benchmark: BenchmarkConfig = Field(..., description="基准配置")
|
||||
|
||||
# 回测
|
||||
backtest: BacktestConfig = Field(..., description="回测配置")
|
||||
|
||||
# 因子
|
||||
factor: FactorConfig = Field(default_factory=FactorConfig, description="因子配置")
|
||||
|
||||
# 轮动
|
||||
rotation: RotationConfig = Field(default_factory=RotationConfig, description="轮动配置")
|
||||
|
||||
# 调仓
|
||||
rebalance: RebalanceConfig = Field(default_factory=RebalanceConfig, description="调仓配置")
|
||||
|
||||
# 溢价控制
|
||||
premium_control: PremiumControlConfig = Field(default_factory=PremiumControlConfig, description="溢价控制")
|
||||
|
||||
# 数据
|
||||
data: DataConfig = Field(..., description="数据配置")
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 通用策略配置 Schema(V2 架构)
|
||||
# ============================================================
|
||||
|
||||
class StrategyConfig(BaseModel):
|
||||
"""
|
||||
通用策略配置(支持所有策略类型)
|
||||
|
||||
使用示例:
|
||||
from framework_v2.config import load_config
|
||||
config = load_config('rotation.yaml')
|
||||
"""
|
||||
metadata: MetadataConfig = Field(default_factory=MetadataConfig, description="元数据")
|
||||
|
||||
# 资产池
|
||||
asset_pools: AssetPool = Field(..., description="资产池配置")
|
||||
|
||||
# 基准
|
||||
benchmark: BenchmarkConfig = Field(..., description="基准配置")
|
||||
|
||||
# 回测
|
||||
backtest: BacktestConfig = Field(..., description="回测配置")
|
||||
|
||||
# 因子
|
||||
factor: FactorConfig = Field(default_factory=FactorConfig, description="因子配置")
|
||||
|
||||
# 轮动(可选)
|
||||
rotation: Optional[RotationConfig] = Field(None, description="轮动配置")
|
||||
|
||||
# 调仓
|
||||
rebalance: RebalanceConfig = Field(default_factory=RebalanceConfig, description="调仓配置")
|
||||
|
||||
# 溢价控制
|
||||
premium_control: PremiumControlConfig = Field(default_factory=PremiumControlConfig, description="溢价控制")
|
||||
|
||||
# 数据
|
||||
data: DataConfig = Field(..., description="数据配置")
|
||||
Reference in New Issue
Block a user