feat: 实现贪心分配模式(greedy)

- config_loader.py: 添加 etf_pool 字段和 GREEDY 枚举
- config_simple.yaml: 每个资产添加 etf_pool 列表
- simple_rotation.py:
  - 添加 _compute_greedy_weights 方法
  - _calculate_daily_return 支持 greedy 模式
  - 向后兼容原有 rank/equal 模式

贪心算法:按 ETF 池容量分配仓位,装不下的顺延给下一名
- 有色金属(1 ETF): 吸收25%,顺延75%
- 原油(3 ETF): 吸收75%
- 黄金(4 ETF): 吸收100%

回测对比 (select_num=3):
- rank: 326.60% 累计收益, 1.24 夏普
- greedy: 421.35% 累计收益, 1.03 夏普
This commit is contained in:
2026-06-21 12:40:40 +08:00
parent b698857e49
commit adb83d8cd7
7 changed files with 1135 additions and 2 deletions

View File

@@ -56,6 +56,7 @@ class WeightType(str, Enum):
EQUAL = "equal" # 等权
RANK = "rank" # 按排名加权 (slot i gets (N-i)/triangular(N))
KELLY = "kelly" # Kelly准则近似 (score-proportional weighting)
GREEDY = "greedy" # 贪心分配按ETF池容量吸收仓位
class DataSourceType(str, Enum):
@@ -82,6 +83,7 @@ class AssetConfig(BaseModel):
signal_source: str = Field(..., description="信号来源代码")
trade_source: str = Field(..., description="交易来源代码")
etf_pool: List[str] = Field(default_factory=list, description="可交易ETF池按规模排序")
description: Optional[str] = Field(None, description="标的描述")
etf: Optional[str] = Field(None, description="ETF代码兼容旧配置")
@@ -179,6 +181,7 @@ class RotationConfig(BaseModel):
diversified: bool = Field(default=True)
threshold: ThresholdConfig = Field(default_factory=ThresholdConfig)
weight: WeightType = Field(default=WeightType.EQUAL)
etf_max_weight: float = Field(default=0.25, ge=0.01, le=1.0)
class RebalanceConfig(BaseModel):