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

> Exploit mispriced multi-outcome events where outcome prices don't sum to $1.00.

<Info>**Pro Feature** -- This requires a Pro or Ultra subscription. [Get started at horizon.mathematicalcompany.com](https://horizon.mathematicalcompany.com)</Info>

When a prediction market event has multiple outcomes (e.g., 4 candidates), their prices should sum to \$1.00. Deviations create arbitrage opportunities.

## Full Code

```python theme={null}
"""Multi-outcome arb: 4-candidate election event."""

import horizon as hz


# Register a multi-outcome event
event = hz.Event(
    event_id="presidential-election-2028",
    outcomes=[
        hz.Outcome(market_id="candidate-a", name="Candidate A"),
        hz.Outcome(market_id="candidate-b", name="Candidate B"),
        hz.Outcome(market_id="candidate-c", name="Candidate C"),
        hz.Outcome(market_id="candidate-d", name="Candidate D"),
    ],
)

# One-shot scan for mispricing
engine = hz.Engine()
engine.register_event(event)

# Start feeds for all outcomes
for outcome in event.outcomes:
    engine.start_feed(
        outcome.market_id,
        "polymarket_book",
        config_json=f'{{"condition_id": "{outcome.market_id}"}}',
    )

# Scan for arb
result = hz.event_arb_scanner(
    engine,
    event_id="presidential-election-2028",
    min_edge=0.005,
)

if result:
    print(f"Event arb found!")
    print(f"  Sum of asks: ${result.total_ask:.4f}")
    print(f"  Edge: ${result.edge:.4f} per full set")
    print(f"  Recommended sizes: {result.sizes}")
else:
    print("No multi-outcome arb found")
```

## How It Works

1. **`Event`** groups related outcomes that must sum to \$1.00
2. **`event_arb_scanner()`** sums the best ask across all outcomes
3. If `total_ask < 1.00`, buying all outcomes locks in a risk-free profit of `1.00 - total_ask`
4. Sizing is proportional: cheaper outcomes get more contracts to balance dollar exposure

## Live Pipeline

Run the scanner continuously inside `hz.run()`:

```python theme={null}
"""Continuous multi-outcome arb scanner."""

import horizon as hz
from horizon.context import FeedData


def fair_value(ctx: hz.Context) -> float:
    """Use Candidate A feed as primary."""
    feed = ctx.feeds.get("candidate-a", FeedData())
    return feed.price if feed.price > 0 else 0.25


event = hz.Event(
    event_id="presidential-election-2028",
    outcomes=[
        hz.Outcome(market_id="candidate-a", name="Candidate A"),
        hz.Outcome(market_id="candidate-b", name="Candidate B"),
        hz.Outcome(market_id="candidate-c", name="Candidate C"),
        hz.Outcome(market_id="candidate-d", name="Candidate D"),
    ],
)

scanner = hz.event_arb_sweep

hz.run(
    name="multi_outcome_arb",
    events=[event],
    markets=["candidate-a", "candidate-b", "candidate-c", "candidate-d"],
    feeds={
        "candidate-a": hz.PolymarketBook("candidate-a"),
        "candidate-b": hz.PolymarketBook("candidate-b"),
        "candidate-c": hz.PolymarketBook("candidate-c"),
        "candidate-d": hz.PolymarketBook("candidate-d"),
    },
    pipeline=[fair_value],
    risk=hz.Risk(max_position=100, max_drawdown_pct=3),
    interval=1.0,
    mode="paper",
)
```

## Run It

```bash theme={null}
python examples/multi_outcome_arb.py
```

## Composite Scanner

Combine parity, cross-exchange, and multi-outcome scanning for maximum coverage:

```python theme={null}
scanner = hz.composite_arb(
    methods=[
        hz.ArbMethodConfig(method="parity", market_id="candidate-a", feed_name="candidate-a"),
        hz.ArbMethodConfig(
            method="event",
            event_id="presidential-election-2028",
        ),
        hz.ArbMethodConfig(
            method="cross_exchange",
            market_id="candidate-a",
            exchanges=["polymarket", "kalshi"],
            feed_map={"polymarket": "candidate-a", "kalshi": "kalshi-candidate-a"},
        ),
    ],
    min_edge=0.005,
    auto_execute=True,
)
```

See [Multi-Outcome Arbitrage](/arbitrage/multi-outcome) for the full method reference.
