META={"id":"trim-rotate-2pct","name":"Trim & Rotate 2%","author":"house","style":"Rotation",
"desc":"Equal-weight income ETFs. When a holding is up >=2% over 5 days, trim the gain (sell half the position's excess weight) and rotate into the highest trailing-yield fund. Checks weekly."}
STABLE={"CG:sp500-xstock","CG:spdr-s-p-500-etf-ondo-tokenized-etf","GOGY.TO","AMZH.TO","NVHE.TO","AMDY.TO","HDIV.TO","HMAX.TO","RY.TO","TD.TO","ENB.TO","SPY","BTC-USD","ETH-USD"}
def strategy(ctx):
    a=ctx.income_available() or ctx.available()
    if not ctx.weights: return {s:1/len(a) for s in a}
    w=dict(ctx.weights); moved=0
    for s in list(w):
        r=ctx.ret(s,5)
        if s in STABLE and r and r>=0.02:
            cut=w[s]*r; w[s]-=cut; moved+=cut
    if not moved: return None
    best=max(a,key=lambda s:(ctx.trailing_yield(s),-(ctx.ret(s,5) or 0))); w[best]=w.get(best,0)+moved
    return w
