Skip to main content
The Fund Portfolio Manager is the top-level layer that treats all strategies as a unified book. It tracks NAV, allocates capital, enforces fund-wide risk limits, and provides fund reporting.

Why It’s Needed

Individual strategies manage their own risk via RiskConfig, but a hedge fund needs:
  • Unified NAV: what is the fund worth right now, across all strategies and exchanges?
  • Capital allocation: how much capital should each strategy get?
  • Fund-wide drawdown limits: if the fund is down 5% this month, reduce all exposure
  • Cross-strategy awareness: two strategies might be making the same bet

Quick Start

from horizon.fund import FundManager, FundConfig, StrategyConfig

# Create the fund
fund = FundManager(FundConfig(
    total_capital=100_000,
    max_fund_drawdown_pct=15.0,
    max_strategy_drawdown_pct=25.0,
))

# Add strategies
fund.add_strategy(StrategyConfig(
    name="political_mm",
    pipeline=[signal, quote],
    markets=["will-x-win", "will-y-happen"],
    mode="paper",
))

fund.add_strategy(StrategyConfig(
    name="crypto_arb",
    pipeline=[detect_arb, execute],
    markets=["btc-100k"],
    mode="paper",
))

# Start everything (deploys strategies + oversight loop)
fund.start()

# Check status
status = fund.status()
# {
#     "running": True,
#     "total_capital": 100000.0,
#     "nav": 100250.0,
#     "drawdown_pct": 0.0,
#     "running_strategies": 2,
#     "total_fees": 12.5,
#     ...
# }

# Generate a full report
report = fund.report()
print(report.nav.total_nav)
print(report.strategies)

# Stop everything
fund.stop()
Real-time net asset value computed by aggregating across all strategy engines.
# NAV is computed each oversight cycle automatically
# You can also access it directly:
nav = fund.nav_engine.compute_nav(fund.controller.engines)
print(f"NAV: ${nav.total_nav:,.2f}")
print(f"Cash: ${nav.cash:,.2f}")
print(f"Positions: ${nav.positions_value:,.2f}")
print(f"Drawdown: {nav.drawdown_pct:.1f}%")
print(f"HWM: ${nav.high_water_mark:,.2f}")

# NAV history
history = fund.nav_history(limit=100)
for snap in history:
    print(f"  {snap.timestamp}: ${snap.total_nav:,.2f}")
NAV formula: NAV = initial_capital + sum(realized_pnl) + sum(unrealized_pnl) across all engines.

Capital Allocation

Multiple allocation methods:
MethodDescription
Equal weightSplit capital equally across strategies
Risk parityAllocate inversely to each strategy’s volatility
Performance-weightedMore capital to higher-performing strategies
CustomUser-defined weights per strategy
from horizon.fund import FundConfig, AllocationMethod

# Equal weight (default)
config = FundConfig(total_capital=100_000, allocation_method=AllocationMethod.EQUAL)

# Custom weights
config = FundConfig(
    total_capital=100_000,
    allocation_method=AllocationMethod.CUSTOM,
    custom_weights={"political_mm": 0.6, "crypto_arb": 0.4},
)

# Dynamic weight updates
fund.allocator.set_custom_weight("political_mm", 0.7)
fund.allocator.set_custom_weight("crypto_arb", 0.3)

Fund Accounting

Fee tracking and P&L attribution per strategy.
# P&L attribution
attr = fund.pnl_attribution()
# {
#     "political_mm": {"realized": 500.0, "unrealized": 150.0, "total": 650.0, "net": 640.0, "fees": 10.0},
#     "crypto_arb": {"realized": 200.0, "unrealized": -50.0, "total": 150.0, "net": 145.0, "fees": 5.0},
# }

# Fee tracking
fund.accounting.record_fee(FeeType.EXCHANGE, 5.0, "political_mm")
print(f"Total fees: ${fund.accounting.total_fees():,.2f}")
print(f"Fees by strategy: {fund.accounting.fees_by_strategy()}")

# Management and performance fees are computed automatically
# during the oversight loop
Management fee: Annual fee accrued daily. Default 200 bps (2%). Performance fee: Fee on profits above the high water mark. Default 20%.

Fund-Wide Risk

Automatic circuit breakers and risk alerts.
# Risk monitoring happens automatically in the oversight loop
# The FundRiskMonitor checks:
# 1. Fund-wide drawdown vs. limit -> activates kill switch
# 2. Per-strategy drawdown vs. limit -> pauses strategy
# 3. Multiple strategy failures -> alerts

# Manual override
fund.risk_monitor.reset_kill_switch()
fund.risk_monitor.clear_strategy_pause("political_mm")

# Check recent alerts
alerts = fund.risk_monitor.recent_alerts()
for alert in alerts:
    print(f"[{alert.level}] {alert.message}")
TriggerAction
Fund drawdown >= limitKill switch: stop all strategies
Fund drawdown >= 80% of limitWarning alert
Strategy drawdown >= limitPause that strategy
3+ strategy failuresCritical alert

Configuration Reference

ParameterDefaultDescription
total_capital100,000Total fund capital in USD
allocation_methodEQUALHow to allocate capital
custom_weightsWeights for CUSTOM method
max_strategies20Max concurrent strategies
max_fund_drawdown_pct15.0Fund-wide drawdown limit
max_strategy_drawdown_pct25.0Per-strategy drawdown limit
max_correlation0.85Max pairwise correlation
rebalance_interval_secs60.0Oversight loop interval
management_fee_bps200Annual management fee (bps)
performance_fee_pct20.0Performance fee (% of profits)

MCP Tools

ToolDescription
fund_statusNAV, returns, risk metrics, capital available
allocate_capitalMove capital between strategies
fund_reportGenerate fund report
fund_drawdownCurrent drawdown metrics and limits