Multi-asset rebalance
Problem: You have separate strategies for equities, crypto, and fx. You want to allocate capital across them and rebalance the composite weekly.
Solution: Sleeve composition via mts1b-portfolio.multi_sleeve.
The setup
Three sleeves, each producing target weights internally:
sleeves = {
"equities_momentum": {
"factor": "f_momentum_12_1",
"universe": "russell-1000",
"rebal": "monthly",
"allocation": 0.5, # 50% of fund NAV
},
"crypto_mean_rev": {
"factor": "f_crypto_realized_vol",
"universe": "crypto-top-10",
"rebal": "weekly",
"allocation": 0.3,
},
"fx_carry": {
"factor": "f_fx_carry",
"universe": "g10-fx",
"rebal": "monthly",
"allocation": 0.2,
},
}
Composition
from mts1b_portfolio.multi_sleeve import compose
from mts1b_oms import OmsClient
oms = OmsClient(fund_id="multi-asset-paper", base_url="http://oms:8001")
# Each rebalance window, run all sleeves, compose, diff against current
async def rebalance(asof):
sleeve_signals = {}
for name, cfg in sleeves.items():
signal = await mts1b_research.run_sleeve(name, asof=asof)
sleeve_signals[name] = {
"weights": signal.weights,
"allocation": cfg["allocation"],
}
composite = compose(sleeves=sleeve_signals, overlay="hrp")
# composite is dict[symbol → target_weight] summing to 1.0 (gross)
current = await oms.get_positions()
diffs = compute_diff(current, composite, nav=await oms.get_nav())
for trade in diffs:
await oms.submit(trade.to_order())
Sleeve overlap handling
If a symbol appears in two sleeves (e.g. SPY in both equities momentum and a hedging sleeve), compose sums the contributions:
sleeves = {
"equities_long": {"weights": {"SPY": 0.4, "QQQ": 0.6}, "allocation": 0.6},
"spy_hedge": {"weights": {"SPY": -0.5}, "allocation": 0.4},
}
composite = compose(sleeves=sleeves, overlay="equal")
# {"SPY": 0.6*0.4 + 0.4*(-0.5) = 0.04,
# "QQQ": 0.6*0.6 = 0.36}
Net SPY exposure is small (mostly hedged); QQQ exposure is positive. The composer hides this complexity from each sleeve.
HRP overlay on sleeve returns
Instead of fixed allocation, derive from each sleeve's historical returns:
composite = compose(
sleeves=sleeve_signals,
overlay="hrp", # HRP on sleeve returns matrix
hrp_lookback_days=252,
)
If equities and crypto are negatively correlated over the last year, HRP gives them more allocation (diversification). If they've recently correlated, less.
Turnover budget
Aggressive composition causes high turnover at the seams (sleeve A says "buy SPY", sleeve B says "sell SPY"). Constrain it:
composite = compose(
sleeves=sleeve_signals,
overlay="hrp",
max_weekly_turnover=0.30, # max 30% of NAV traded per week
)
The composer solves a constrained problem: minimize tracking error to target while respecting the turnover cap.
Capacity gating
If the equities momentum sleeve wants to buy $50k of a $20m ADV stock and your envelope says max_position_pct=1% of ADV, the order is capped:
from mts1b_portfolio.capacity import position_capacity
cap = position_capacity(symbol="TINY_CORP", nav_usd=fund_nav, fraction_of_adv=0.01)
order_qty = min(target_qty, cap / order.limit_price)
mts1b-riskengine enforces this as a hard gate. The composer respects it proactively so the order isn't rejected.
Reporting
After rebalance:
from mts1b_reportslibrary import sleeve_report
report = await sleeve_report(
fund_id="multi-asset-paper",
sleeves=list(sleeves.keys()),
window="ytd",
)
# Per-sleeve P/L, Sharpe, contribution to fund return, turnover
print(report.to_table())
See also
mts1b-portfolio.multi_sleeve— composition primitivesmts1b-treasury— multi-fund allocator (one level up)- Cookbook: Sizing correlated — HRP overlays in depth