FundCluster
Multi-fund orchestration with shared risk budgeting
FundCluster is v1’s multi-fund orchestrator. You register multiple sub-funds (each one is its own strategy portfolio with its own capital budget), and the cluster coordinates them. shared risk budget enforcement, cross-fund correlation checks, centralized promotion management.
Why multi-fund?
Running many strategies as a single fund has limits:
- Correlation control: if all strategies are equity mean-reversion, they’re correlated
- Attribution noise: it’s hard to know which strategy is driving returns
- Independent risk budgets: a blowup in strategy A shouldn’t take down strategy B
- Different timeframes: daily and intraday strategies want different risk controls
A FundCluster lets you keep strategies separate at the risk and attribution level while coordinating at the capital allocation level.
API
from horizon.fund._multi_fund import FundCluster, SubFund, FundAllocation
cluster = FundCluster(
name="horizon_main",
total_capital_usd=10_000_000,
risk_budget_pct=0.30, # max 30% of capital at risk
)
# Register sub-funds
cluster.add_fund(SubFund(
name="equity_mr",
capital_allocation=3_000_000,
asset_classes=["equity"],
strategies=[BollingerMeanRev(window=20), TSMomentum(lookback=20)],
risk_budget=0.10,
))
cluster.add_fund(SubFund(
name="options_vol",
capital_allocation=2_000_000,
asset_classes=["option"],
strategies=[StraddleStrategy()],
risk_budget=0.08,
))
# Run all funds
results = cluster.run_all(
mode="backtest",
data_sources={...},
backtest=hz.BacktestConfig(...),
)
# Per-fund results
for fund_name, result in results.items():
print(f"{fund_name}:")
print(f" Sharpe: {result.sharpe:+.3f}")
print(f" Drawdown: {result.max_drawdown:.2%}")
Risk budgeting
Each sub-fund gets an independent risk budget (drawdown limit). The cluster enforces:
- Per-fund drawdown: if a fund hits its individual drawdown cap, it’s halted independently
- Cluster drawdown: if total cluster drawdown exceeds
cluster_risk_budget, all funds halt - Cross-fund correlation: if funds become too correlated (e.g., all hitting their stops at the same time), the cluster reduces overall exposure
cluster_risk = cluster.snapshot_risk()
print(f"Cluster drawdown: {cluster_risk.cluster_drawdown:.2%}")
print(f"Per-fund drawdowns:")
for fund_name, dd in cluster_risk.fund_drawdowns.items():
print(f" {fund_name}: {dd:.2%}")
if cluster_risk.cross_fund_correlation > 0.8:
print("⚠️ Funds highly correlated. reducing total exposure")
Dynamic reallocation
FundCluster supports dynamic reallocation: moving capital from underperforming funds to outperforming ones based on rolling Sharpe:
allocation = cluster.suggest_reallocation(
method="sharpe_weighted", # or "ic_weighted", "equal_risk"
lookback_days=60,
)
for fund_name, new_pct in allocation.items():
print(f"{fund_name}: {new_pct:.0%} of total")
cluster.apply_allocation(allocation)
Available methods:
| Method | Description |
|---|---|
sharpe_weighted | Higher Sharpe → more capital |
ic_weighted | Higher realized IC → more capital |
equal_risk | Scale by 1/vol so each fund contributes equal risk |
fixed | No reallocation |
Integration with Horizon
Use FundCluster as a top-level controller when you have multiple logically-distinct strategy books:
import horizon as hz
from horizon.fund._multi_fund import FundCluster, SubFund
from horizon.quant import BollingerMeanRev, TSMomentum
cluster = FundCluster(
name="production",
total_capital_usd=1_000_000,
)
cluster.add_fund(SubFund(
name="us_equity_mr",
capital_allocation=400_000,
asset_classes=["equity"],
strategies=[BollingerMeanRev(window=20)],
))
cluster.add_fund(SubFund(
name="us_equity_mom",
capital_allocation=400_000,
asset_classes=["equity"],
strategies=[TSMomentum(lookback=20)],
))
# Run all funds concurrently, each with its own budget
results = cluster.run_all(mode="paper", ...)
# Risk snapshot across the cluster
print(cluster.snapshot_risk())
When to use
Pitfalls
Source
python/horizon/fund/_multi_fund.py. ~500 lines.