宏观保温杯修改
由bqzzgc5a创建,最终由bqzzgc5a 被浏览 2 用户
万老师的宏观保温杯的约束函数是:
def apply_weight_constraints(weights):
w = dict(weights)
if w.get('债券', 0) > BOND_CAP:
w['债券'] = BOND_CAP
for k in w:
w[k] = min(w[k], WEIGHT_CAP)
for k in ASSETS:
w[k] = max(w.get(k, 0), WEIGHT_FLOOR)
total = sum(w.values())
return {k: v / total for k, v in w.items()}
而若先把债券压到 BOND_CAP,最后又整体归一化。归一化之后,债券可能重新超过 BOND_CAP。
举例:
债券先被压到 20%
其他资产很低
总和只有 50%
归一化后债券 = 20% / 50% = 40%
所以当前约束不是严格约束。
可以改成一个迭代式约束函数:
def apply_weight_constraints(weights: dict, max_iter=20) -> dict:
"""
严格执行:
1. 单资产上限 WEIGHT_CAP
2. 债券专项上限 BOND_CAP
3. 单资产下限 WEIGHT_FLOOR
4. 权重和为 1
"""
w = pd.Series(weights, dtype=float).reindex(ASSETS).fillna(0.0)
lower = pd.Series(WEIGHT_FLOOR, index=ASSETS)
upper = pd.Series(WEIGHT_CAP, index=ASSETS)
upper['债券'] = min(upper['债券'], BOND_CAP)
if lower.sum() > 1:
raise ValueError("WEIGHT_FLOOR 设置过高,所有资产下限之和超过 100%")
w = w.clip(lower=0)
if w.sum() <= 0:
w[:] = 1.0 / len(w)
else:
w = w / w.sum()
fixed = pd.Series(False, index=ASSETS)
for _ in range(max_iter):
old = w.copy()
below = w < lower
above = w > upper
w[below] = lower[below]
w[above] = upper[above]
fixed = below | above
free = ~fixed
remaining = 1.0 - w[fixed].sum()
if remaining < -1e-8:
raise ValueError("上下限约束不可行,请降低 floor 或 cap")
if free.any():
free_sum = old[free].sum()
if free_sum > 0:
w[free] = old[free] / free_sum * remaining
else:
w[free] = remaining / free.sum()
if np.allclose(w.sum(), 1.0, atol=1e-8) and (w >= lower - 1e-8).all() and (w <= upper + 1e-8).all():
break
return w.to_dict()
\