> ## 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.

# Horizon hz.run()

> The single entry point for running a Horizon strategy.

`hz.run()` is the single entry point for running a strategy. It creates the engine, starts feeds, recovers state, syncs positions, and enters the main loop.

## Full Signature

```python theme={null}
hz.run(
    name: str,                                    # Strategy name
    exchange: Exchange | None = None,             # Single exchange config
    exchanges: list[Exchange] | None = None,      # Multi-exchange configs
    markets: list[str] | None = None,             # Market IDs/slugs
    feeds: dict[str, Feed] | None = None,         # Named feeds
    pipeline: list[Callable] | None = None,       # Pipeline functions
    risk: Risk | RiskConfig | None = None,        # Risk limits
    interval: float = 0.5,                        # Seconds between cycles
    mode: str = "paper",                          # "paper" or "live"
    dashboard: bool = False,                      # Show TUI dashboard
    params: dict[str, Any] | None = None,         # Custom params → ctx.params
    db_path: str | None = ...,                    # SQLite path (... = auto)
    events: list[Event] | None = None,                   # Multi-outcome events
    netting_pairs: list[tuple[str, str]] | None = None,  # Position netting
    api_key: str | None = None,  # API key (or use HORIZON_API_KEY env)
)
```

## Parameters

| Parameter       | Type                 | Default   | Description                                                                                                             |
| --------------- | -------------------- | --------- | ----------------------------------------------------------------------------------------------------------------------- |
| `name`          | `str`                | required  | Strategy name (shown in logs and dashboard)                                                                             |
| `exchange`      | `Exchange or None`   | `None`    | Single exchange config: `Polymarket(...)`, `Kalshi(...)`, `Alpaca(...)`, `IBKR(...)`, `Coinbase(...)`, `Robinhood(...)` |
| `exchanges`     | `list`               | `None`    | Multi-exchange configs, e.g. `[Polymarket(...), Alpaca(...)]`                                                           |
| `markets`       | `list[str]`          | `[]`      | Market slugs or tickers to trade                                                                                        |
| `feeds`         | `dict[str, Feed]`    | `{}`      | Named feeds, e.g. `{"btc": BinanceWS("btcusdt")}`                                                                       |
| `pipeline`      | `list[Callable]`     | required  | Pipeline functions. Final fn must return `list[Quote]`                                                                  |
| `risk`          | `Risk or RiskConfig` | defaults  | Risk configuration                                                                                                      |
| `interval`      | `float`              | `0.5`     | Seconds between strategy cycles                                                                                         |
| `mode`          | `str`                | `"paper"` | `"paper"` for simulation, `"live"` for real trading                                                                     |
| `dashboard`     | `bool`               | `False`   | Enable TUI dashboard                                                                                                    |
| `params`        | `dict`               | `{}`      | Custom params accessible via `ctx.params`                                                                               |
| `db_path`       | `str or None`        | auto      | SQLite path. Default: `HORIZON_DB` env or `./{name}.db`. Set `None` to disable.                                         |
| `events`        | `list[Event]`        | `None`    | Multi-outcome events (each outcome becomes a market). See [Multi-Outcome Events](/multi-outcome).                       |
| `netting_pairs` | `list[tuple]`        | `None`    | Market pairs whose positions offset for risk                                                                            |
| `api_key`       | `str or None`        | `None`    | Horizon API key. Falls back to `HORIZON_API_KEY` env var. See [Authentication](/authentication).                        |

<Warning>
  `exchange` and `exchanges` are mutually exclusive. Use `exchange` for single-exchange mode or `exchanges` for multi-exchange mode.
</Warning>

## Lifecycle

<Steps>
  <Step title="Validate API key">
    Validates the Horizon API key (from `api_key` param or `HORIZON_API_KEY` env var). Uses a local cache at `~/.horizon/license.json` - only makes a network call if the cache is expired or missing. See [Authentication](/authentication).
  </Step>

  <Step title="Build engine">
    Creates the Engine with exchange backend(s) and risk config. For multi-exchange, the first exchange in the list becomes the primary.
  </Step>

  <Step title="Register events and netting pairs">
    If `events` is provided, each event is registered on the engine and its outcomes are expanded into markets. If `netting_pairs` is provided, registers each pair on the engine for cross-exchange hedging.
  </Step>

  <Step title="Recover state">
    If persistence is enabled, loads the latest position snapshot and replays fills since that snapshot. Detects orphaned orders from previous runs.
  </Step>

  <Step title="Resolve markets">
    In live mode, fetches market metadata from exchange APIs. For Polymarket, queries the Gamma API for token IDs and condition IDs. For Kalshi, sets the ticker. For Alpaca/IBKR, resolves symbols directly.
  </Step>

  <Step title="Start feeds">
    Starts all configured feeds (WebSocket connections, REST pollers) on the engine's feed manager.
  </Step>

  <Step title="Sync positions">
    In live mode, syncs positions from each exchange to reconcile local state.
  </Step>

  <Step title="Main loop">
    Each cycle:

    * Poll fills from live exchanges
    * Update daily P\&L for drawdown tracking
    * For each market: build context → run pipeline → process result
    * Cancel stale orders → submit new quotes
    * Snapshot positions to DB every 50 cycles
    * Evict terminal orders every 100 cycles
  </Step>

  <Step title="Shutdown">
    On `Ctrl+C` or `SIGTERM`: snapshot positions, end run record, cancel all orders (with 5s timeout), stop feeds.
  </Step>
</Steps>

## Persistence Defaults

The `db_path` parameter uses a sentinel value (`...`) to distinguish between "use default" and "explicitly disabled":

| Value           | Behavior                                   |
| --------------- | ------------------------------------------ |
| `...` (default) | Use `HORIZON_DB` env var, or `./{name}.db` |
| `"/path/to/db"` | Use the specified path                     |
| `None`          | Disable persistence entirely               |

## Authentication

Every call to `hz.run()` requires a valid Horizon API key. There are three ways to provide it:

### Option 1: Explicit `api_key` parameter (clearest)

```python theme={null}
hz.run(
    name="my_strategy",
    api_key="hz_sdk_abc123...",  # Your key from api.mathematicalcompany.com
    markets=["test-market"],
    pipeline=[fair_value, quoter],
)
```

This is the most explicit approach and works in notebooks, scripts, and CI pipelines.

### Option 2: Environment variable (recommended for production)

```bash theme={null}
export HORIZON_API_KEY="hz_sdk_abc123..."
```

```python theme={null}
# No api_key needed -- reads from HORIZON_API_KEY automatically
hz.run(
    name="my_strategy",
    markets=["test-market"],
    pipeline=[fair_value, quoter],
)
```

### Option 3: Saved credentials (programmatic setup)

If you used `horizon.auth.setup()` or the CLI `horizon setup`, your key is saved encrypted at `~/.horizon/credentials.json` and loaded automatically.

### Key formats

| Prefix     | Source                                                                       | Description                        |
| ---------- | ---------------------------------------------------------------------------- | ---------------------------------- |
| `hz_live_` | Website ([api.mathematicalcompany.com](https://api.mathematicalcompany.com)) | Manual signup key                  |
| `hz_sdk_`  | `horizon.auth.setup()` or CLI                                                | Programmatically generated SDK key |

Both formats work identically. The `hz_sdk_` keys are generated via the SDK's auth module and are useful for automated/agentic setups where no browser is available.

### Resolution order

| Priority | Source                                         |
| -------- | ---------------------------------------------- |
| 1        | `api_key` param in `hz.run()`                  |
| 2        | `HORIZON_API_KEY` environment variable         |
| 3        | `~/.horizon/credentials.json` (saved by setup) |

See [Authentication](/authentication) for the full guide.

## Examples

### Paper trading (simplest)

```python theme={null}
hz.run(
    name="simple",
    api_key="hz_sdk_abc123...",  # or set HORIZON_API_KEY env var
    markets=["test-market"],
    pipeline=[fair_value, quoter],
    risk=hz.Risk(max_position=100),
)
```

### Live on Polymarket

```python theme={null}
hz.run(
    name="poly_mm",
    api_key="hz_sdk_abc123...",  # or set HORIZON_API_KEY env var
    exchange=hz.Polymarket(private_key="0x..."),
    markets=["will-btc-hit-100k"],
    feeds={"btc": hz.BinanceWS("btcusdt")},
    pipeline=[fair_value, quoter],
    risk=hz.Risk(max_position=100),
    mode="live",
    dashboard=True,
)
```

### Equity trading on Alpaca

```python theme={null}
hz.run(
    name="aapl_mm",
    exchange=hz.Alpaca(paper=True),
    markets=[hz.Market(id="AAPL", exchange="alpaca", ticker="AAPL", asset_class="equity")],
    feeds={"aapl": hz.AlpacaFeed(symbols=["AAPL"])},
    pipeline=[fair_value, quoter],
    risk=hz.Risk.equity(max_position=100, max_notional=50_000),
    mode="live",
)
```

### Multi-asset (prediction market + stocks)

```python theme={null}
hz.run(
    name="hedged",
    exchanges=[hz.Polymarket(private_key="0x..."), hz.Alpaca(paper=True)],
    markets=[
        hz.Market(id="will-fed-cut", exchange="polymarket"),
        hz.Market(id="TLT", exchange="alpaca", asset_class="equity"),
    ],
    feeds={
        "rates": hz.PolymarketBook("will-fed-cut"),
        "tlt": hz.AlpacaFeed(symbols=["TLT"]),
    },
    pipeline=[cross_asset_strategy],
    risk=hz.Risk(max_position=100, price_min=0.01, price_max=1000),
    mode="live",
)
```

### Multi-outcome events

```python theme={null}
events = hz.discover_events("polymarket", query="election", limit=5)

hz.run(
    name="event_mm",
    exchange=hz.Polymarket(private_key="0x..."),
    events=events,
    pipeline=[fair_value, quoter],
    risk=hz.RiskConfig(max_position_per_market=50, max_position_per_event=150),
    mode="live",
)
```

See [Multi-Outcome Events](/multi-outcome) for the full guide.

### Multi-exchange with netting

```python theme={null}
hz.run(
    name="cross_venue",
    exchanges=[
        hz.Polymarket(private_key="0x..."),
        hz.Kalshi(api_key="..."),
    ],
    markets=["btc-100k-poly", "KXBTC-25FEB16"],
    feeds={"btc": hz.BinanceWS("btcusdt")},
    pipeline=[fair_value, quoter],
    risk=hz.Risk(max_position=50),
    mode="live",
    netting_pairs=[("btc-100k-poly", "KXBTC-25FEB16")],
)
```
