> ## Documentation Index
> Fetch the complete documentation index at: https://mathematicalcompany.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Fund Operations

> Alerts, double-entry ledger, paper-to-live promotion, and self-healing recovery.

Operational infrastructure that runs alongside the oversight loop. These subsystems handle notifications, accounting, strategy promotion, and automatic recovery from failures.

## Alerts and Notifications

Rate-limited alert system with multi-channel delivery. Alerts fire during the oversight loop for risk events, kill switch activations, strategy failures, and settlements.

### Alert Levels and Categories

| Level      | Use                                                      |
| ---------- | -------------------------------------------------------- |
| `INFO`     | Routine events (settlement detected, strategy promoted)  |
| `WARNING`  | Approaching limits (80% drawdown, strategy paused)       |
| `CRITICAL` | Immediate action needed (kill switch, multiple failures) |

| Category           | Triggered By                                 |
| ------------------ | -------------------------------------------- |
| `KILL_SWITCH`      | Fund drawdown exceeds limit                  |
| `STRATEGY_FAILURE` | Strategy thread crashes                      |
| `DRAWDOWN`         | Fund or strategy drawdown approaching limit  |
| `SETTLEMENT`       | Market resolved, P\&L booked                 |
| `CORRELATION`      | Cross-strategy correlation exceeds threshold |
| `RISK_LIMIT`       | VaR budget breach                            |
| `RECOVERY`         | Self-healing restart attempt                 |
| `PROMOTION`        | Strategy promoted to next stage              |
| `REBALANCE`        | Capital reallocation triggered               |
| `GENERAL`          | Everything else                              |

### Rate Limiting

Each category is limited to 5 alerts per 60 seconds. Excess alerts are silently dropped to prevent notification floods during volatile periods.

### Channels

```python theme={null}
from horizon.fund import FundConfig

# Webhook channel -- delivers alerts via HTTP POST
fund = FundManager(FundConfig(
    total_capital=100_000,
    alert_webhook_url="https://hooks.slack.com/services/...",
))

# The webhook sends JSON:
# {
#     "level": "CRITICAL",
#     "category": "KILL_SWITCH",
#     "title": "Kill switch activated",
#     "message": "Fund drawdown 15.2% exceeded limit 15.0%",
#     "timestamp": "2026-03-13T14:30:00.000000"
# }
```

Webhook delivery runs in a background thread to avoid blocking the oversight loop. Failed deliveries are logged but do not retry.

### MCP Tool

```
fund_alerts(limit=50)
```

Returns recent alerts with counts by category. Use this to check what happened while the LLM was idle.

## Double-Entry Ledger

SQLite-backed accounting ledger that records every financial event as a debit/credit journal entry. Provides balance sheet and income statement views.

### Accounts

| Account            | Type    | Tracks                         |
| ------------------ | ------- | ------------------------------ |
| `CASH`             | Asset   | Available capital              |
| `POSITIONS`        | Asset   | Capital deployed in positions  |
| `FEES_RECEIVABLE`  | Asset   | Fees owed (internal)           |
| `MANAGEMENT_FEES`  | Revenue | Annual management fee accruals |
| `PERFORMANCE_FEES` | Revenue | Performance fee accruals       |
| `REALIZED_PNL`     | Revenue | Booked profit and loss         |
| `UNREALIZED_PNL`   | Revenue | Mark-to-market P\&L            |

### Journal Entries

Every financial event creates a balanced journal entry:

| Event            | Debit             | Credit           | Amount            |
| ---------------- | ----------------- | ---------------- | ----------------- |
| Deposit          | CASH              | (external)       | Deposit amount    |
| Withdrawal       | (external)        | CASH             | Withdrawal amount |
| Profitable trade | CASH              | REALIZED\_PNL    | Profit            |
| Losing trade     | REALIZED\_PNL     | CASH             | Loss              |
| Management fee   | MANAGEMENT\_FEES  | FEES\_RECEIVABLE | Fee amount        |
| Performance fee  | PERFORMANCE\_FEES | FEES\_RECEIVABLE | Fee amount        |

### Configuration

```python theme={null}
fund = FundManager(FundConfig(
    total_capital=100_000,
    ledger_enabled=True,  # Enable double-entry ledger
))
```

When enabled, the oversight loop automatically records:

* Settlement P\&L when markets resolve
* Management and performance fee accruals each tick
* All amounts validated (must be finite, positive)

### MCP Tool

```
fund_ledger(limit=50)
```

Returns recent journal entries, balance sheet (assets vs. liabilities), and income statement.

### Reports

```python theme={null}
# Balance sheet
bs = fund.ledger.balance_sheet()
# {"CASH": 95000.0, "POSITIONS": 5000.0, "MANAGEMENT_FEES": 200.0, ...}

# Income statement
inc = fund.ledger.income_statement()
# {"REALIZED_PNL": 1500.0, "MANAGEMENT_FEES": -200.0, "PERFORMANCE_FEES": -100.0}

# Recent entries
entries = fund.ledger.recent_entries(limit=20)
```

## Paper-to-Live Promotion

Structured lifecycle that gates strategy promotion behind performance criteria. Strategies must prove themselves in paper trading before progressing to shadow mode and then live trading.

### Promotion Stages

```
PAPER --> SHADOW --> LIVE
```

| Stage      | Description                                  |
| ---------- | -------------------------------------------- |
| **PAPER**  | Simulated execution, no real capital         |
| **SHADOW** | Runs alongside live but orders not submitted |
| **LIVE**   | Real execution with real capital             |

### Promotion Criteria

Each transition requires meeting minimum thresholds:

| Criteria           | Default | Description                   |
| ------------------ | ------- | ----------------------------- |
| `min_paper_days`   | 14      | Minimum days in current stage |
| `min_trades`       | 50      | Minimum number of trades      |
| `min_sharpe`       | 1.0     | Minimum Sharpe ratio          |
| `max_drawdown_pct` | 20.0    | Maximum drawdown percentage   |
| `min_win_rate`     | 0.45    | Minimum win rate              |

### Configuration

```python theme={null}
fund = FundManager(FundConfig(
    total_capital=100_000,
    promotion_enabled=True,  # Enable promotion lifecycle
))
```

When enabled, the oversight loop checks promotion eligibility every 60 ticks. Promotions are recorded with a full audit trail in SQLite (strategy name, from/to stage, timestamp, metrics at promotion time).

### MCP Tool

```
fund_promotion_status()
```

Returns current promotion stage for each strategy and promotion history.

### Persistence

Two SQLite tables track state:

* `promotions`: current stage per strategy
* `promotion_history`: every promotion event with timestamp and reason

Data is stored in `~/.horizon/promotion.db` with WAL mode and `0o600` permissions.

## Self-Healing Recovery

Automatic strategy restart with exponential backoff and circuit breaker. Detects failed strategies and stale feeds, attempts recovery without human intervention.

### How It Works

1. The oversight loop calls `recovery.check_strategies()` every 10 ticks
2. For each failed strategy, it attempts a restart via `controller.restart()`
3. If the restart fails, backoff doubles: 60s, 120s, 240s...
4. After 3 failed attempts, the circuit breaker opens and the strategy is marked permanently failed

### Circuit Breaker

| Attempt | Cooldown | Action                                |
| ------- | -------- | ------------------------------------- |
| 1       | 60s      | Restart strategy                      |
| 2       | 120s     | Restart strategy                      |
| 3       | 240s     | Restart strategy                      |
| 4+      | --       | Circuit breaker open, no more retries |

To re-enable recovery for a permanently failed strategy:

```python theme={null}
fund.recovery.reset("strategy_name")
```

### Feed Monitoring

The recovery manager also detects stale feeds (no update for 300+ seconds) and logs warnings. Feed staleness is informational; automatic feed reconnection is handled by the feed manager.

### Configuration

```python theme={null}
fund = FundManager(FundConfig(
    total_capital=100_000,
    self_healing_enabled=True,  # Enable self-healing
))
```

### Recovery Events

Every recovery attempt is logged:

```python theme={null}
events = fund.recovery.event_history(limit=20)
# [
#     RecoveryEvent(
#         action="restart_strategy",
#         target="political_mm",
#         success=True,
#         attempt=1,
#         error=None,
#     ),
# ]

stats = fund.recovery.stats()
# {"total_attempts": 5, "successes": 3, "failures": 2, "circuit_breakers_open": 1}
```

## Configuration Summary

| Parameter              | Default | Description                    |
| ---------------------- | ------- | ------------------------------ |
| `alert_webhook_url`    | None    | Webhook URL for alert delivery |
| `ledger_enabled`       | False   | Enable double-entry accounting |
| `promotion_enabled`    | False   | Enable paper-to-live promotion |
| `self_healing_enabled` | False   | Enable automatic recovery      |

All four subsystems are off by default. Enable them individually in `FundConfig`. They integrate with the oversight loop automatically when enabled.
