---
title: "Resolution Sniping"
description: "Detect resolution events in real-time and capture payout with aggressive positioning."
icon: "crosshairs"
---

Resolution Sniping monitors news sources and uses LLM analysis to detect when a prediction market's underlying event has resolved. When resolution is detected with high confidence, it generates aggressive quotes to buy the resolving side near parity.

## Standalone Scan

```python
import horizon as hz

markets = [
    {"id": "market-1", "title": "Will team X win the championship?"},
    {"id": "market-2", "title": "Will bill Y pass the Senate?"},
]

signals = hz.scan_resolutions(markets)
for s in signals:
    print(f"{s.market_title}: resolved={s.resolved} side={s.resolution_side}")
    print(f"  Confidence: {s.confidence:.2%}")
    print(f"  Evidence: {s.evidence}")
```

## Pipeline Mode

Integrate sniping into your `hz.run()` pipeline:

```python
hz.run(
    name="sniper-bot",
    markets=["championship-2026", "senate-bill-xyz"],
    feeds={"poly": hz.PolymarketBook("championship-2026")},
    pipeline=[hz.resolution_sniper()],
)
```

When resolution is detected:
1. Fetches latest news from configured RSS sources
2. LLM evaluates if the event has definitively resolved
3. If confidence >= threshold: generates aggressive quote at near-parity
4. Tracks already-triggered markets to avoid double-sniping

## Configuration

```python
config = hz.SniperConfig(
    provider="anthropic",           # or "openai", or any litellm provider
    model="",                       # empty = provider default; or "openrouter/..."
    news_sources=[                  # RSS feeds to monitor
        "https://feeds.bbci.co.uk/news/rss.xml",
    ],
    exa_query="election results",   # Exa.ai semantic search (optional)
    tavily_query="vote count",      # Tavily real-time search (optional)
    confidence_threshold=0.85,      # minimum confidence to trigger
    max_position_size=50.0,         # max USDC per snipe
    price_offset=0.02,              # offset from 1.0 for pricing
    scan_interval_cycles=5,         # cycles between scans
    cache_ttl=60.0,                 # signal cache TTL
)

hz.run(
    pipeline=[hz.resolution_sniper(config=config)],
    ...
)
```

## Kalshi Markets

The MCP `sniper_scan` tool supports Kalshi markets via the `exchange` parameter. Market discovery will pull from Kalshi instead of Polymarket:

```python
# Via MCP tool
sniper_scan(exchange="kalshi")
```

The resolution detection logic (news + LLM) is exchange-agnostic: it works identically for both Polymarket and Kalshi markets.

## How It Works

```
News Feed -> LLM Analysis -> Resolution Signal -> Aggressive Quote
                                |
                        confidence >= 0.85?
                           /        \
                         yes         no
                          |           |
                    Generate Quote   Skip
                    (bid=0.98)
```

## Confidence Tuning

| Threshold | Behavior |
|-----------|----------|
| 0.95+ | Very conservative, few false positives |
| 0.85 (default) | Balanced sensitivity |
| 0.70 | Aggressive, more false positives |

Higher confidence = fewer trades but higher accuracy. Lower confidence = more trades but risk of sniping before actual resolution.

## Types

### ResolutionSignal

| Field | Type | Description |
|-------|------|-------------|
| `market_id` | `str` | Market identifier |
| `market_title` | `str` | Market question |
| `resolved` | `bool` | Whether event appears resolved |
| `confidence` | `float` | Detection confidence [0, 1] |
| `resolution_side` | `str` | "yes" or "no" |
| `evidence` | `list[str]` | Triggering headlines |
| `reasoning` | `str` | LLM reasoning |
| `timestamp` | `float` | Unix timestamp |

### SniperConfig

| Field | Default | Description |
|-------|---------|-------------|
| `provider` | `"anthropic"` | LLM provider (or any litellm provider) |
| `model` | `""` | Model name. Accepts litellm strings like `"openrouter/..."` |
| `news_sources` | `[]` | RSS feed URLs |
| `exa_query` | `""` | Exa.ai semantic search query |
| `tavily_query` | `""` | Tavily real-time search query |
| `confidence_threshold` | `0.85` | Min confidence to trigger |
| `max_position_size` | `50.0` | Max USDC per snipe |
| `price_offset` | `0.02` | Offset from parity |
| `scan_interval_cycles` | `5` | Cycles between scans |
| `cache_ttl` | `60.0` | Signal cache TTL |
