---
title: "Quant Swarm"
description: "Deploy multiple autonomous agents that research, discover alpha, backtest, deploy capital, trade, and self-manage, coordinated by a central fund cluster."
icon: "bugs"
---

Multiple autonomous agents, each independently searching for opportunities across exchanges and asset classes. No predefined strategies. Each agent searches from scratch, forms hypotheses, backtests them, deploys capital, trades, monitors positions, retires underperformers, and scales up what works. A central cluster coordinates capital allocation, risk budgets, and aggregate monitoring.

<Note>
  **Ultra Feature.** Requires an Ultra subscription. [Get started at api.mathematicalcompany.com](https://api.mathematicalcompany.com)
</Note>

## The Idea

Instead of writing strategies by hand, you launch agents and let them do the work. Each agent:

1. **Scans** its assigned universe for mispriced markets
2. **Forms hypotheses** ("Market X is mispriced because Y")
3. **Constructs a pipeline** from composable building blocks
4. **Backtests** with robustness checks (BiasGuard blocks overfitting)
5. **Deploys in paper**, auto-promotes to shadow, then live
6. **Trades** on live exchanges (submit, cancel, amend)
7. **Monitors** P&L, drawdown, alpha decay, execution quality
8. **Retires** dead strategies, frees capital, loops back to step 1

A `FundCluster` sits above all agents, aggregating NAV, enforcing cross-agent risk limits, and rebalancing capital.

## Architecture

<CardGroup cols={2}>
  <Card title="FundCluster" icon="sitemap">
    Central coordinator. Aggregates NAV across all agents, monitors cross-fund risk, rebalances capital, and routes alerts.
  </Card>
  <Card title="Per-Agent FundManager" icon="microchip">
    Each agent is a full FundManager with all 36 subsystems: research, alpha model, hypothesis lifecycle, backtest, bias guard, promotion, execution, decay tracking, adaptive thresholds, recovery.
  </Card>
</CardGroup>

### Agent Domains

<CardGroup cols={3}>
  <Card title="Crypto" icon="bitcoin-sign">
    Polymarket + Coinbase feeds. BTC, ETH, SOL prediction markets.
  </Card>
  <Card title="Politics" icon="landmark">
    Polymarket + Kalshi. Election and policy event markets.
  </Card>
  <Card title="Sports" icon="football">
    Kalshi. Game outcomes, championships, season props.
  </Card>
  <Card title="Macro/Rates" icon="chart-line">
    Kalshi + IBKR ForecastEx. Fed rates, CPI, treasury yields.
  </Card>
  <Card title="Cross-Exchange" icon="arrows-cross">
    Polymarket + Kalshi. Same-market arbitrage across venues.
  </Card>
  <Card title="Tail Risk" icon="bolt">
    Polymarket. Low-probability, high-payoff event bets.
  </Card>
  <Card title="High Frequency" icon="gauge-high">
    Polymarket. Short-lived mispricings, fast rebalance cycle (15s).
  </Card>
</CardGroup>

Each agent connects to its own exchanges and runs independently. The cluster only aggregates and rebalances.

## Step 1: Define Pipeline Building Blocks

Instead of hardcoding strategies, define composable building blocks that agents can assemble into pipelines. Each block is a standard pipeline function.

```python
"""swarm_blocks.py - Composable pipeline building blocks."""

import math
import horizon as hz


# ──────────────────────────────────────────────
# Fair value estimators
# ──────────────────────────────────────────────

def mean_reversion_fair(ctx: hz.Context) -> float:
    """Fade extremes toward 0.50. Works on any binary market."""
    feed = ctx.feeds.get("book", hz.context.FeedData())
    mid = feed.price if feed.price > 0 else 0.50
    strength = ctx.params.get("mr_strength", 0.3)
    fair = mid + (0.50 - mid) * strength
    return max(0.05, min(0.95, fair))


def momentum_fair(ctx: hz.Context) -> float:
    """Trend-following: extrapolate recent price direction."""
    feed = ctx.feeds.get("book", hz.context.FeedData())
    mid = feed.price if feed.price > 0 else 0.50
    history = ctx.params.setdefault("_price_buf", [])
    history.append(mid)
    if len(history) > 100:
        history.pop(0)
    if len(history) < 10:
        return mid
    recent = sum(history[-5:]) / 5
    older = sum(history[-20:-10]) / 10
    drift = (recent - older) * ctx.params.get("mom_scale", 2.0)
    return max(0.05, min(0.95, mid + drift))


def oracle_fair(ctx: hz.Context) -> float:
    """Use external oracle feed as fair value anchor."""
    oracle = ctx.feeds.get("oracle", hz.context.FeedData())
    book = ctx.feeds.get("book", hz.context.FeedData())
    if oracle.price > 0:
        return max(0.05, min(0.95, oracle.price))
    return book.price if book.price > 0 else 0.50


def ensemble_fair(ctx: hz.Context) -> float:
    """Blend mean-reversion and momentum based on regime."""
    mr = mean_reversion_fair(ctx)
    mom = momentum_fair(ctx)
    regime = ctx.params.get("regime", "calm")
    if regime == "volatile":
        return 0.7 * mr + 0.3 * mom  # favor MR in chaos
    elif regime == "trending":
        return 0.3 * mr + 0.7 * mom  # favor momentum in trends
    return 0.5 * mr + 0.5 * mom


# ──────────────────────────────────────────────
# Quoters
# ──────────────────────────────────────────────

def adaptive_quoter(ctx: hz.Context, fair: float) -> list[hz.Quote]:
    """Kelly-sized quotes with inventory-adjusted spread."""
    inv = ctx.inventory.net if hasattr(ctx.inventory, "net") else 0.0
    book = ctx.feeds.get("book", hz.context.FeedData())
    market_mid = book.price if book.price > 0 else 0.50

    # Only quote when there's edge
    min_edge = ctx.params.get("min_edge", 0.02)
    if abs(fair - market_mid) < min_edge:
        return []

    base_spread = ctx.params.get("base_spread", 0.04)
    spread = base_spread + abs(inv) * 0.001

    bankroll = ctx.params.get("bankroll", 10_000)
    size = hz.kelly(prob=fair, market_price=market_mid, bankroll=bankroll)
    max_size = ctx.params.get("max_size", 30.0)
    size = max(1.0, min(max_size, size))

    return hz.quotes(fair, spread, size=size)


def directional_quoter(ctx: hz.Context, fair: float) -> list[hz.Quote]:
    """One-sided quoting: only buy underpriced or sell overpriced."""
    book = ctx.feeds.get("book", hz.context.FeedData())
    market_mid = book.price if book.price > 0 else 0.50

    min_edge = ctx.params.get("min_edge", 0.03)
    edge = fair - market_mid
    if abs(edge) < min_edge:
        return []

    bankroll = ctx.params.get("bankroll", 10_000)
    size = hz.kelly(prob=fair, market_price=market_mid, bankroll=bankroll)
    size = max(1.0, min(ctx.params.get("max_size", 20.0), size))

    if edge > 0:
        return [hz.Quote(side=hz.Side.Yes, order_side=hz.OrderSide.Buy,
                         price=market_mid + 0.01, size=size)]
    else:
        return [hz.Quote(side=hz.Side.Yes, order_side=hz.OrderSide.Sell,
                         price=market_mid - 0.01, size=size)]


# ──────────────────────────────────────────────
# Pipeline templates (agents pick from these)
# ──────────────────────────────────────────────

PIPELINE_TEMPLATES = {
    "mean_reversion_mm": [mean_reversion_fair, adaptive_quoter],
    "momentum_mm": [momentum_fair, adaptive_quoter],
    "oracle_mm": [oracle_fair, adaptive_quoter],
    "ensemble_mm": [ensemble_fair, adaptive_quoter],
    "mr_directional": [mean_reversion_fair, directional_quoter],
    "momentum_directional": [momentum_fair, directional_quoter],
    "oracle_directional": [oracle_fair, directional_quoter],
}
```

## Step 2: Create an Agent Factory

Each agent is a `FundManager` configured for a specific domain. The factory creates agents with all autonomous features enabled.

```python
"""swarm_factory.py -Create autonomous fund agents."""

import os
from horizon.fund import FundManager, FundConfig, StrategyConfig
import horizon as hz


def create_agent(
    name: str,
    capital: float,
    exchanges: list,
    drawdown_pct: float = 15.0,
    rebalance_secs: float = 60.0,
    alert_webhook: str | None = None,
) -> FundManager:
    """
    Create a fully autonomous fund agent.

    Every subsystem is enabled: regime detection, alpha model,
    hypothesis lifecycle, backtest runner, bias guard, promotion,
    recovery, adaptive thresholds, execution intelligence, ledger.

    No manual input needed after start().
    """
    config = FundConfig(
        total_capital=capital,

        # Risk
        max_fund_drawdown_pct=drawdown_pct,
        max_strategy_drawdown_pct=drawdown_pct + 5.0,
        max_correlation=0.80,

        # Timing
        rebalance_interval_secs=rebalance_secs,

        # Fees (track internally even on paper)
        management_fee_bps=200,
        performance_fee_pct=20.0,

        # Enable every autonomous subsystem
        optimization_enabled=True,        # Kelly + Ledoit-Wolf portfolio optimizer
        regime_risk_enabled=True,          # Regime-conditional risk limits
        ledger_enabled=True,              # Double-entry accounting
        promotion_enabled=True,           # Paper -> shadow -> live lifecycle
        self_healing_enabled=True,        # Recovery manager + circuit breaker
        adaptive_thresholds_enabled=True, # Learn from decision outcomes

        # Alerts
        alert_webhook_url=alert_webhook or "",
    )

    fund = FundManager(config)
    fund._agent_name = name  # tag for logging

    return fund
```

## Step 3: Launch the Swarm

Create specialized agents for different market domains and wire them into a central cluster.

```python
"""quant_swarm.py -Launch and run the full swarm."""

import os
import time
import threading
from horizon.fund import FundCluster, StrategyConfig
import horizon as hz

from swarm_factory import create_agent
from swarm_blocks import PIPELINE_TEMPLATES


# ============================================================
# Configuration
# ============================================================

TOTAL_CAPITAL = 500_000
WEBHOOK = os.environ.get("SWARM_WEBHOOK_URL", "")

# Capital allocation across agents
AGENT_ALLOCATIONS = {
    "crypto_hunter":     0.25,   # $125k, crypto prediction markets
    "politics_scanner":  0.20,   # $100k, political event markets
    "sports_edge":       0.15,   # $75k, sports outcome markets
    "macro_rates":       0.15,   # $75k, macro/rates/treasury
    "cross_exchange":    0.10,   # $50k, cross-exchange arbitrage
    "tail_risk":         0.10,   # $50k, tail / low-probability events
    "high_frequency":    0.05,   # $25k, short-lived opportunities
}


# ============================================================
# Create the agents
# ============================================================

agents = {}

# Agent 1: Crypto markets -Polymarket + Coinbase feeds
agents["crypto_hunter"] = create_agent(
    name="crypto_hunter",
    capital=TOTAL_CAPITAL * AGENT_ALLOCATIONS["crypto_hunter"],
    exchanges=[
        hz.Polymarket(
            private_key=os.environ.get("POLYMARKET_PRIVATE_KEY", ""),
            api_key=os.environ.get("POLYMARKET_API_KEY"),
            api_secret=os.environ.get("POLYMARKET_API_SECRET"),
            api_passphrase=os.environ.get("POLYMARKET_API_PASSPHRASE"),
        ),
    ],
    drawdown_pct=20.0,
    alert_webhook=WEBHOOK,
)

# Agent 2: Political event markets -Polymarket + Kalshi
agents["politics_scanner"] = create_agent(
    name="politics_scanner",
    capital=TOTAL_CAPITAL * AGENT_ALLOCATIONS["politics_scanner"],
    exchanges=[
        hz.Polymarket(
            private_key=os.environ.get("POLYMARKET_PRIVATE_KEY", ""),
            api_key=os.environ.get("POLYMARKET_API_KEY"),
            api_secret=os.environ.get("POLYMARKET_API_SECRET"),
            api_passphrase=os.environ.get("POLYMARKET_API_PASSPHRASE"),
        ),
        hz.Kalshi(api_key=os.environ.get("KALSHI_API_KEY", "")),
    ],
    drawdown_pct=12.0,
    alert_webhook=WEBHOOK,
)

# Agent 3: Sports outcome markets -Kalshi
agents["sports_edge"] = create_agent(
    name="sports_edge",
    capital=TOTAL_CAPITAL * AGENT_ALLOCATIONS["sports_edge"],
    exchanges=[
        hz.Kalshi(api_key=os.environ.get("KALSHI_API_KEY", "")),
    ],
    drawdown_pct=15.0,
    alert_webhook=WEBHOOK,
)

# Agent 4: Macro/rates -Kalshi + IBKR for ForecastEx
agents["macro_rates"] = create_agent(
    name="macro_rates",
    capital=TOTAL_CAPITAL * AGENT_ALLOCATIONS["macro_rates"],
    exchanges=[
        hz.Kalshi(api_key=os.environ.get("KALSHI_API_KEY", "")),
        hz.IBKR(
            host=os.environ.get("IBKR_HOST", "localhost"),
            port=int(os.environ.get("IBKR_PORT", "5000")),
        ),
    ],
    drawdown_pct=10.0,   # tighter limits on macro
    alert_webhook=WEBHOOK,
)

# Agent 5: Cross-exchange arbitrage, all exchanges
agents["cross_exchange"] = create_agent(
    name="cross_exchange",
    capital=TOTAL_CAPITAL * AGENT_ALLOCATIONS["cross_exchange"],
    exchanges=[
        hz.Polymarket(
            private_key=os.environ.get("POLYMARKET_PRIVATE_KEY", ""),
            api_key=os.environ.get("POLYMARKET_API_KEY"),
            api_secret=os.environ.get("POLYMARKET_API_SECRET"),
            api_passphrase=os.environ.get("POLYMARKET_API_PASSPHRASE"),
        ),
        hz.Kalshi(api_key=os.environ.get("KALSHI_API_KEY", "")),
    ],
    drawdown_pct=8.0,    # arb should have low drawdown
    rebalance_secs=30.0,  # faster cycle for arb
    alert_webhook=WEBHOOK,
)

# Agent 6: Tail risk / low-probability events
agents["tail_risk"] = create_agent(
    name="tail_risk",
    capital=TOTAL_CAPITAL * AGENT_ALLOCATIONS["tail_risk"],
    exchanges=[
        hz.Polymarket(
            private_key=os.environ.get("POLYMARKET_PRIVATE_KEY", ""),
            api_key=os.environ.get("POLYMARKET_API_KEY"),
            api_secret=os.environ.get("POLYMARKET_API_SECRET"),
            api_passphrase=os.environ.get("POLYMARKET_API_PASSPHRASE"),
        ),
    ],
    drawdown_pct=30.0,   # loose limits, tail bets are volatile
    alert_webhook=WEBHOOK,
)

# Agent 7: High-frequency short-lived opportunities
agents["high_frequency"] = create_agent(
    name="high_frequency",
    capital=TOTAL_CAPITAL * AGENT_ALLOCATIONS["high_frequency"],
    exchanges=[
        hz.Polymarket(
            private_key=os.environ.get("POLYMARKET_PRIVATE_KEY", ""),
            api_key=os.environ.get("POLYMARKET_API_KEY"),
            api_secret=os.environ.get("POLYMARKET_API_SECRET"),
            api_passphrase=os.environ.get("POLYMARKET_API_PASSPHRASE"),
        ),
    ],
    drawdown_pct=15.0,
    rebalance_secs=15.0,  # fastest cycle
    alert_webhook=WEBHOOK,
)


# ============================================================
# Seed each agent with initial strategy templates
# ============================================================

# Each agent gets a few pipeline templates to start with.
# The autonomous loop will discover markets, backtest, and deploy on its own.
# These seeds just give each agent a starting point.

def seed_agent(agent: FundManager, domain: str, templates: list[str], markets: list[str]):
    """Give an agent initial strategies to explore. All start in paper mode."""
    for template_name in templates:
        pipeline = PIPELINE_TEMPLATES.get(template_name)
        if not pipeline:
            continue
        for market in markets:
            agent.add_strategy(StrategyConfig(
                name=f"{domain}_{template_name}_{market}",
                pipeline=pipeline,
                markets=[market],
                mode="paper",  # always start paper, promotion manager handles the rest
            ))


# Crypto agent: scan BTC, ETH, SOL prediction markets
seed_agent(agents["crypto_hunter"], "crypto",
           ["ensemble_mm", "momentum_directional"],
           ["btc-above-100k", "eth-above-5k"])

# Politics agent: scan election and policy markets
seed_agent(agents["politics_scanner"], "politics",
           ["mean_reversion_mm", "oracle_directional"],
           ["will-x-win-2028", "will-y-pass"])

# Sports agent: scan game outcome markets
seed_agent(agents["sports_edge"], "sports",
           ["mean_reversion_mm", "mr_directional"],
           ["nba-finals-winner", "superbowl-2027"])

# Macro agent: rates and economic indicators
seed_agent(agents["macro_rates"], "macro",
           ["oracle_mm", "momentum_directional"],
           ["fed-rate-cut-june", "cpi-above-3-pct"])

# Arb agent: look for cross-exchange mispricings
seed_agent(agents["cross_exchange"], "arb",
           ["ensemble_mm"],
           ["btc-above-100k", "will-x-win-2028"])

# Tail risk: cheap options on unlikely events
seed_agent(agents["tail_risk"], "tail",
           ["mr_directional"],
           ["major-earthquake-2027"])

# HF agent: fast markets with tight spreads
seed_agent(agents["high_frequency"], "hf",
           ["momentum_mm", "mean_reversion_mm"],
           ["btc-above-100k"])


# ============================================================
# Wire into FundCluster
# ============================================================

cluster = FundCluster()
for name, agent in agents.items():
    cluster.add_fund(name, agent)


# ============================================================
# Launch the swarm
# ============================================================

print("=" * 60)
print("  QUANT SWARM - Launching agents")
print("=" * 60)
print(f"  Total capital:  ${TOTAL_CAPITAL:,.0f}")
print(f"  Agents:         {len(agents)}")
print()

for name, alloc in AGENT_ALLOCATIONS.items():
    capital = TOTAL_CAPITAL * alloc
    print(f"  {name:20s}  ${capital:>10,.0f}  ({alloc:.0%})")

print()
print("  Starting all agents...")

cluster.start_all()

print("  All agents running. Oversight loops active.")
print("=" * 60)


# ============================================================
# Central monitoring loop
# ============================================================

def monitor_swarm(cluster: FundCluster, interval: float = 60.0):
    """
    Central monitoring thread. Prints aggregate status and
    rebalances capital if any agent drifts too far from target.
    """
    while True:
        try:
            status = cluster.aggregate_status()
            risk = cluster.aggregate_risk()

            print(f"\n{'─' * 60}")
            print(f"  SWARM STATUS | NAV: ${status['total_nav']:,.0f}")
            print(f"  Weighted Drawdown: {risk['weighted_avg_drawdown_pct']:.1f}%")
            print(f"  Max Single Agent:  {risk['max_drawdown_fund']} "
                  f"({risk['max_single_fund_drawdown_pct']:.1f}%)")
            print(f"{'─' * 60}")

            for name, fund_status in status["funds"].items():
                nav = fund_status["nav"]
                dd = fund_status["drawdown_pct"]
                strats = fund_status.get("running_strategies", 0)
                ks = fund_status.get("kill_switch", False)
                flag = " KILL SWITCH" if ks else ""
                print(f"  {name:20s}  NAV=${nav:>10,.0f}  DD={dd:5.1f}%  "
                      f"strategies={strats}{flag}")

            # Check if any agent needs rebalancing (>20% drift from target)
            total_nav = status["total_nav"]
            if total_nav > 0:
                for name, target_pct in AGENT_ALLOCATIONS.items():
                    if name not in status["funds"]:
                        continue
                    actual_pct = status["funds"][name]["nav"] / total_nav
                    drift = abs(actual_pct - target_pct)
                    if drift > 0.20 * target_pct:
                        print(f"  ** {name} drifted {drift:.1%} from target -"
                              f"consider rebalancing")

            time.sleep(interval)

        except Exception as e:
            print(f"  Monitor error: {e}")
            time.sleep(interval)


# Run monitor in background
monitor_thread = threading.Thread(
    target=monitor_swarm,
    args=(cluster, 60.0),
    daemon=True,
)
monitor_thread.start()

# Main thread keeps running
try:
    while True:
        time.sleep(1)
except KeyboardInterrupt:
    print("\nShutting down swarm...")
    cluster.stop_all()
    print("All agents stopped.")
```

## What Each Agent Does Autonomously

After `cluster.start_all()`, each agent runs this loop on every rebalance cycle:

| Tick | What Happens | Module |
|------|-------------|--------|
| Every 60s | Compute NAV, check kill switch | NAVEngine, FundRiskMonitor |
| Every 60s | Update regime (calm/volatile/crisis) | RegimeDetector (3-state HMM) |
| Every 60s | Monitor VPIN toxicity per market | ExecutionIntelligence |
| Every 60s | Detect settlements, book P&L | SettlementMonitor |
| Every 60s | Accrue fees, update correlations | FundAccounting, CorrelationMonitor |
| Every 60s | Record fill quality, adapt execution | ExecutionQualityTracker |
| Every 60s | Consume research triggers | ResearchIntelligence |
| Every 5 ticks | Compute portfolio Greeks | RiskAnalytics |
| Every 5 ticks | Rebalance capital across strategies | CapitalAllocator |
| Every 5 ticks | Optimize portfolio (Kelly + Ledoit-Wolf) | PortfolioOptimizer |
| Every 60 ticks | Check alpha decay, emit alerts | AlphaDecayTracker |
| Every 60 ticks | Update VaR budgets | VaRBudgetManager |
| Every 60 ticks | Snapshot attribution (alpha/beta) | PerformanceAttribution |
| Every 120 ticks | Tune confidence thresholds from outcomes | ThresholdTuner |

### Research to Deploy Cycle

Each agent's `ResearchIntelligence` watches for 6 trigger types:

1. **Regime change**: HMM detects shift from calm to volatile
2. **Cross-market divergence**: two correlated markets diverge >5%
3. **Volume spike**: 2x+ median volume
4. **New market**: fresh market appears on exchange
5. **Edge refresh**: edge increases on existing market
6. **Settlement cascade**: resolution frees capital for new positions

When a trigger fires, the agent:

```
Trigger → AlphaModel (7-factor edge estimate)
       → HypothesisManager (form hypothesis with Bayesian confidence)
       → BacktestRunner (500-tick synthetic backtest)
       → BiasGuard (screen for 5 overfitting types)
       → PromotionManager (deploy in paper if all gates pass)
       → ... 14 days paper, 7 days shadow ...
       → Live trading with real capital
```

### Deployment Gates (all must pass)

| Gate | Threshold | Purpose |
|------|-----------|---------|
| Sharpe ratio | >= 1.0 | Minimum risk-adjusted return |
| Trades | >= 30 | Statistical significance |
| P-value | < 0.05 | Not due to luck (Benjamini-Hochberg corrected) |
| Walk-forward | > 60% OOS windows positive | Not overfit |
| PBO | < 50% | Probability of backtest overfitting |
| BiasGuard | All 5 checks pass | No recency/confirmation/chasing bias |

## Step 4: LLM Control via MCP

Expose each agent as an MCP server so an LLM can check status, intervene, and rebalance.

### One MCP Server Per Agent

```json
{
  "mcpServers": {
    "swarm-crypto": {
      "command": "python",
      "args": ["-m", "horizon.mcp_fund"],
      "env": {
        "HORIZON_FUND_MODE": "1",
        "HORIZON_AGENT_NAME": "crypto_hunter"
      }
    },
    "swarm-politics": {
      "command": "python",
      "args": ["-m", "horizon.mcp_fund"],
      "env": {
        "HORIZON_FUND_MODE": "1",
        "HORIZON_AGENT_NAME": "politics_scanner"
      }
    },
    "swarm-sports": {
      "command": "python",
      "args": ["-m", "horizon.mcp_fund"],
      "env": {
        "HORIZON_FUND_MODE": "1",
        "HORIZON_AGENT_NAME": "sports_edge"
      }
    }
  }
}
```

### What the LLM Can Do

The LLM gets 32 fund tools per agent. Example interactions:

| LLM Command | Tools Called | Effect |
|---|---|---|
| "What's the swarm doing?" | `fund_status` on each agent | Aggregate health check |
| "Why is crypto_hunter losing money?" | `fund_explain_strategy`, `fund_decay_report` | Root cause analysis |
| "Shift 10% from sports to politics" | `allocate_capital` on both | Cross-agent rebalance |
| "Kill all tail risk positions" | `stop_strategy` on tail_risk agent | Emergency shutdown |
| "Show me all hypotheses across agents" | `fund_hypotheses` on each | Research overview |
| "What regime are we in?" | `fund_regime` on each | Market condition check |
| "Stress test the whole swarm" | `stress_test_fund` on each | Portfolio resilience |

## Step 5: Scaling the Swarm

### Add More Agents Dynamically

```python
# Spin up a new agent at runtime
weather_agent = create_agent(
    name="weather_bets",
    capital=25_000,
    exchanges=[hz.Kalshi(api_key=os.environ.get("KALSHI_API_KEY", ""))],
    drawdown_pct=20.0,
    alert_webhook=WEBHOOK,
)

seed_agent(weather_agent, "weather",
           ["mean_reversion_mm"],
           ["hurricane-season-above-avg"])

cluster.add_fund("weather_bets", weather_agent)
weather_agent.start()
```

### Remove Underperforming Agents

```python
# Check which agent is dragging
risk = cluster.aggregate_risk()
worst = risk["max_drawdown_fund"]

# Stop and remove it
worst_fund = cluster.fund(worst)
worst_fund.stop()
cluster.remove_fund(worst)

# Redistribute its capital
targets = cluster.rebalance_across_funds({
    name: 1.0 / (len(agents) - 1)
    for name in cluster.fund_names
})
```

### Per-Agent Explainability

Query any agent for explanations:

```python
# Why did crypto_hunter deploy this strategy?
crypto = cluster.fund("crypto_hunter")
explanation = crypto.explain()
# Returns: overview, regime, risk, strategies, decisions,
#          alerts, hypotheses, alpha factors (structured dict)

# Deep dive on a specific strategy
strat_explain = crypto.explain_strategy("crypto_ensemble_mm_btc-above-100k")
# Returns: performance, execution quality, alpha decay,
#          promotion stage, hypothesis state

# Full risk picture
risk_explain = crypto.explain_risk()
# Returns: tail risk, Greeks, correlations, stress results,
#          VaR budget, risk limits, attribution breakdown
```

## Operating Modes

Control how much autonomy each agent gets:

```python
from horizon.fund import AutonomousAgent

# Dry-run: LLM proposes, human approves every action
for name, agent in agents.items():
    AutonomousAgent(fund=agent, mode="dry_run")

# Supervised: auto-execute low-risk, escalate high-risk
for name, agent in agents.items():
    AutonomousAgent(fund=agent, mode="supervised")

# Autonomous: executes all actions within guardrails
for name, agent in agents.items():
    AutonomousAgent(fund=agent, mode="autonomous")
```

| Mode | Paper Deploy | Live Deploy | Kill Switch | Scale Up |
|------|-------------|------------|-------------|----------|
| Dry-run | Human approves | Human approves | Human approves | Human approves |
| Supervised | Auto | Human approves | Human approves | Human approves |
| Autonomous | Auto | Auto (after gates) | Auto | Auto (after gates) |

Even in autonomous mode, every agent still enforces:
- Rate limits (max 3 deploys/hour, max 10 capital changes/day)
- Confidence thresholds (0.5 for paper, 0.7 for live, 0.8 for scale-up)
- BiasGuard (5 overfitting checks)
- Promotion gates (14 days paper, 7 days shadow)
- Fund drawdown kill switch
- SHA-256 hash-chained audit trail on every decision

## Summary

Running `python quant_swarm.py` gives you:

- **7 agents** each running the full research-to-retirement loop
- **Central cluster** with aggregate NAV, risk, and rebalancing
- **Cross-agent correlation monitoring**: the cluster flags correlated bets across agents
- **Persistent memory**: each agent remembers outcomes across restarts (SQLite)
- **Recovery**: if a strategy crashes, RecoveryManager restarts it with a circuit breaker
- **Adaptive execution**: each agent tunes spreads, sizes, and timing from fill quality data
- **Alpha decay tracking**: agents retire strategies when edge erodes
- **Audit trail**: every decision logged with reasoning, confidence, and outcome
- **MCP interface**: an LLM can observe and steer the swarm via 32 tools per agent

No predefined strategies. No manual intervention. The agents search, test, deploy, trade, monitor, learn, and repeat.
