fix: greedy模式从所有信号中顺延,而非仅holdings列表
问题:select_num=1时,holdings只有1个元素,ETF池不足时仓位闲置 - 有色金属(1ETF): 仓位25%,75%闲置 - 德国DAX(2ETF): 仓位50%,50%闲置 - 原油(3ETF): 仓位75%,25%闲置 修复:从所有信号中按动量排序顺延 - 有色金属(25%) → 顺延到第2名信号(如原油75%) → 100%满配 回测对比 (select_num=1): - equal: 1053% 累计收益, 1.34 夏普 - greedy(修复前): 730% 累计收益, 1.31 夏普 - greedy(修复后): 1355% 累计收益, 1.69 夏普
This commit is contained in:
@@ -531,9 +531,10 @@ class SimpleRotationStrategy:
|
||||
"""Compute greedy weights for signal-level holdings.
|
||||
|
||||
Greedy Algorithm (only for select_num=1):
|
||||
1. The top-1 index has absorption capacity = min(n_etfs, ceil(1/max_weight)) × max_weight
|
||||
2. If capacity < 100%, remaining weight flows to next index by momentum
|
||||
3. Continue until 100% allocated
|
||||
1. Get ALL signals sorted by momentum (not just holdings)
|
||||
2. The top signal has absorption capacity = min(n_etfs, ceil(1/max_weight)) × max_weight
|
||||
3. If capacity < 100%, remaining weight flows to next signal by momentum
|
||||
4. Continue until 100% allocated
|
||||
|
||||
Example (select_num=1, max_weight=0.25):
|
||||
- 有色金属(1 ETF): capacity=25%, absorbs 25%, remaining=75%
|
||||
@@ -558,10 +559,17 @@ class SimpleRotationStrategy:
|
||||
w = 1.0 / len(holdings)
|
||||
return {code: w for code in holdings}
|
||||
|
||||
# Get ALL signals sorted by momentum (for spill-over)
|
||||
all_signals_sorted = sorted(
|
||||
self.signal_codes,
|
||||
key=lambda c: factors.get(c, 0),
|
||||
reverse=True
|
||||
)
|
||||
|
||||
signal_weights = {}
|
||||
remaining_weight = 1.0
|
||||
|
||||
for signal_code in holdings:
|
||||
for signal_code in all_signals_sorted:
|
||||
if remaining_weight <= 0:
|
||||
break
|
||||
|
||||
@@ -579,6 +587,7 @@ class SimpleRotationStrategy:
|
||||
remaining_weight -= absorb
|
||||
|
||||
# Assign weight to this signal
|
||||
if absorb > 0:
|
||||
signal_weights[signal_code] = absorb
|
||||
|
||||
return signal_weights
|
||||
|
||||
Reference in New Issue
Block a user