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

# Composite Scanner

> Meta-scanner that scores all arbitrage methods and routes capital to the best opportunities.

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

# Composite Arbitrage Scanner

A meta-scanner that runs all configured arbitrage methods, scores opportunities, and routes capital to the best ones. The ultimate arbitrage tool for running a full arb desk.

## How It Works

1. Configure which arb methods to run with weights and capital limits
2. Each cycle, the composite scanner checks `ctx.params` for results from individual scanners
3. Score each opportunity: `score = (net_edge / cost) * confidence * weight * (1 - utilization)`
4. Rank and execute the top-N (limited by `max_concurrent` and `total_capital`)

## ArbMethodConfig

```python theme={null}
method = hz.ArbMethodConfig(
    method="parity",          # Method name
    weight=1.0,               # Scoring weight
    max_capital=500.0,        # Capital limit for this method
    enabled=True,             # Enable/disable
    kwargs={"size": 50.0},    # Extra parameters
)
```

| Field         | Type    | Default  | Description                                                                          |
| ------------- | ------- | -------- | ------------------------------------------------------------------------------------ |
| `method`      | `str`   | required | `"parity"`, `"cross_exchange"`, `"event"`, `"spread"`, `"stat"`, `"mm"`, `"latency"` |
| `weight`      | `float` | `1.0`    | Scoring weight multiplier                                                            |
| `max_capital` | `float` | `500.0`  | Max capital for this method                                                          |
| `enabled`     | `bool`  | `True`   | Whether to include in scans                                                          |
| `kwargs`      | `dict`  | `{}`     | Extra parameters                                                                     |

## Pipeline: composite\_arb

```python theme={null}
scanner = hz.composite_arb(
    methods=[
        hz.ArbMethodConfig(method="parity", weight=2.0),
        hz.ArbMethodConfig(method="cross_exchange", weight=1.5),
        hz.ArbMethodConfig(method="event", weight=1.0),
        hz.ArbMethodConfig(method="spread", weight=0.8),
        hz.ArbMethodConfig(method="stat", weight=1.0),
        hz.ArbMethodConfig(method="latency", weight=2.0),
    ],
    total_capital=1000.0,
    max_concurrent=3,
    rebalance_interval=60.0,
    auto_execute=False,
    cooldown=5.0,
)
```

| Parameter            | Type                    | Default  | Description                    |
| -------------------- | ----------------------- | -------- | ------------------------------ |
| `methods`            | `list[ArbMethodConfig]` | required | Methods to run                 |
| `total_capital`      | `float`                 | `1000.0` | Total capital budget           |
| `max_concurrent`     | `int`                   | `3`      | Max simultaneous positions     |
| `rebalance_interval` | `float`                 | `60.0`   | Seconds between rebalancing    |
| `auto_execute`       | `bool`                  | `False`  | Auto-execute top opportunities |
| `cooldown`           | `float`                 | `5.0`    | Seconds between executions     |

Stores `list[CompositeArbResult]` in `ctx.params["last_composite_arb"]`.

## CompositeArbResult

| Field            | Type    | Description                            |
| ---------------- | ------- | -------------------------------------- |
| `method`         | `str`   | Which arb method found the opportunity |
| `score`          | `float` | Composite score                        |
| `net_edge`       | `float` | Expected edge                          |
| `capital_needed` | `float` | Capital required                       |
| `details`        | `dict`  | Method-specific details                |
| `timestamp`      | `float` | Detection timestamp                    |

## Example: Full Arb Desk

```python theme={null}
import horizon as hz

# Individual scanners feed results into ctx.params
parity = hz.parity_arb_scanner(
    "election-winner",
    exchange="polymarket",
    feed_name="polymarket",
    auto_execute=False,
)
cross = hz.arb_scanner(
    "election-winner",
    exchanges=["polymarket", "kalshi"],
    feed_map={"polymarket": "polymarket", "kalshi": "kalshi"},
)
spread = hz.spread_convergence(
    "gop-senate", "gop-house",
    "gop_senate_feed", "gop_house_feed",
)

# Composite scanner reads their results and decides what to execute
composite = hz.composite_arb(
    methods=[
        hz.ArbMethodConfig(method="parity", weight=2.0),
        hz.ArbMethodConfig(method="cross_exchange", weight=1.5),
        hz.ArbMethodConfig(method="spread", weight=0.8),
    ],
    total_capital=5000.0,
    max_concurrent=2,
    rebalance_interval=30.0,
    auto_execute=True,
)

hz.run(
    name="arb_desk",
    exchanges=[
        hz.Polymarket(private_key="0x..."),
        hz.Kalshi(api_key="..."),
    ],
    markets=["election-winner", "gop-senate", "gop-house"],
    feeds={
        "polymarket": hz.PolymarketBook("election-winner"),
        "kalshi": hz.KalshiBook("KXELECTION-25"),
        "gop_senate_feed": hz.PolymarketBook("gop-senate"),
        "gop_house_feed": hz.PolymarketBook("gop-house"),
    },
    pipeline=[parity, cross, spread, composite],
    interval=0.5,
)
```

<Note>
  The composite scanner reads results from individual scanners via `ctx.params`. Run individual scanners earlier in the pipeline so their results are available when the composite scanner runs.
</Note>
