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

# Multi-Outcome Arb

> Event-level arbitrage when N outcome prices don't sum to $1.00.

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

# Multi-Outcome Arbitrage

When an event has N outcomes (e.g., 4 candidates in an election), the sum of all YES prices should equal \$1.00. If it doesn't, there's an arbitrage opportunity.

## How It Works

* **Sum \< \$1.00 - fees**: Buy all outcomes. One will resolve to \$1.00, so you profit the difference.
* **Sum > \$1.00 + fees**: Sell all outcomes (buy all NOs). You collect more than \$1.00 upfront.

```
Trump:    $0.30
Biden:    $0.25
DeSantis: $0.20
Other:    $0.15
Sum:      $0.90 (< $1.00)
Edge:     $0.10 - fees
Action:   Buy all outcomes
```

## Engine Methods

### scan\_event\_arb

```python theme={null}
engine.register_event("election", ["trump", "biden", "desantis", "other"])

opp = engine.scan_event_arb("election", fee_rate=0.002)
# Returns EventArbitrageOpportunity or None
```

### execute\_event\_arb

```python theme={null}
order_ids = engine.execute_event_arb(
    event_id="election",
    direction="buy_all",   # or "sell_all"
    size=50.0,
    proportional=True,     # Size inversely proportional to price
)
```

N-leg atomic execution. If any leg fails, all prior legs are canceled.

When `proportional=True`: cheaper outcomes get more contracts so cost is balanced across legs.

## Pipeline: event\_arb\_scanner

```python theme={null}
scanner = hz.event_arb_scanner(
    event_id="election",
    min_edge=0.01,
    max_size=50.0,
    fee_rate=0.002,
    auto_execute=True,
    cooldown=10.0,
    proportional=True,
)

hz.run(pipeline=[scanner], ...)
```

| Parameter      | Type    | Default  | Description                 |
| -------------- | ------- | -------- | --------------------------- |
| `event_id`     | `str`   | required | Registered event ID         |
| `min_edge`     | `float` | `0.01`   | Minimum net edge            |
| `max_size`     | `float` | `50.0`   | Maximum total size          |
| `fee_rate`     | `float` | `0.002`  | Fee rate per outcome        |
| `auto_execute` | `bool`  | `False`  | Auto-execute                |
| `cooldown`     | `float` | `10.0`   | Seconds between executions  |
| `proportional` | `bool`  | `True`   | Inverse-proportional sizing |

Stores `EventArbitrageOpportunity` in `ctx.params["last_event_arb"]`.

## One-Shot: event\_arb\_sweep

```python theme={null}
result = hz.event_arb_sweep(engine, "election", min_edge=0.01)

if result:
    print(f"Direction: {result.direction}, Edge: {result.net_edge:.4f}")
    print(f"Order IDs: {result.order_ids}")
```

Returns `EventArbResult` or `None`.

## EventArbResult

| Field       | Type        | Description                 |
| ----------- | ----------- | --------------------------- |
| `event_id`  | `str`       | Event identifier            |
| `direction` | `str`       | `"buy_all"` or `"sell_all"` |
| `price_sum` | `float`     | Sum of all outcome prices   |
| `net_edge`  | `float`     | Edge after fees             |
| `size`      | `float`     | Trade size                  |
| `order_ids` | `list[str]` | Order IDs for each leg      |
| `timestamp` | `float`     | Execution timestamp         |

<Note>
  Register events with `engine.register_event(event_id, market_ids)` before scanning. Each market needs a corresponding feed for price data.
</Note>

***

## Logical Arb Scanners

Beyond price-sum arbitrage, Horizon detects logical relationship violations between related markets.

### hz.implication\_arb\_scanner

For markets where A implies B (e.g., "Biden wins" implies "Democrat wins"), the price of A must be less than or equal to the price of B. Violations are arbs.

```python theme={null}
scanner = hz.implication_arb_scanner(
    markets=["biden-wins", "dem-wins", "trump-wins", "gop-wins"],
    implications=[
        ("biden-wins", "dem-wins"),     # Biden wins => Democrat wins
        ("trump-wins", "gop-wins"),     # Trump wins => GOP wins
    ],
    min_edge=0.02,
)

hz.run(pipeline=[scanner], ...)
# Injects ctx.params["implication_arbs"] = [
#   {"type": "implication", "market_a": ..., "market_b": ..., "edge": ..., "action": ...}
# ]
```

| Parameter      | Type                    | Description                                    |
| -------------- | ----------------------- | ---------------------------------------------- |
| `markets`      | `list[str]`             | Market IDs to monitor                          |
| `implications` | `list[tuple[str, str]]` | `(A, B)` pairs where A implies B               |
| `min_edge`     | `float`                 | Minimum price violation to flag (default 0.01) |

### hz.contradiction\_arb\_scanner

For mutually exclusive markets (e.g., "Trump wins" and "Biden wins"), the sum of prices must be at most 1.0. If `P(A) + P(B) > 1`, sell both.

```python theme={null}
scanner = hz.contradiction_arb_scanner(
    markets=["trump-wins", "biden-wins"],
    contradictions=[
        ("trump-wins", "biden-wins"),  # Can't both win
    ],
    min_edge=0.02,
)

hz.run(pipeline=[scanner], ...)
# Injects ctx.params["contradiction_arbs"] = [
#   {"type": "contradiction", "market_a": ..., "price_sum": ..., "edge": ..., "action": ...}
# ]
```

| Parameter        | Type                    | Description                                            |
| ---------------- | ----------------------- | ------------------------------------------------------ |
| `markets`        | `list[str]`             | Market IDs to monitor                                  |
| `contradictions` | `list[tuple[str, str]]` | `(A, B)` pairs that are mutually exclusive             |
| `min_edge`       | `float`                 | Minimum sum violation above 1.0 to flag (default 0.01) |
