BigQuant 2026年度私享会

宏观保温杯修改

由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()

\

{link}