---
title: "Breeden-Litzenberger"
description: "Extract risk-neutral probability densities from options chains and compute cross-asset edge signals for prediction markets."
icon: "bridge"
---

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

<Tip>
  **What is this?** Options prices on stocks, crypto, and commodities contain information about the market's probability distribution for future prices. Breeden-Litzenberger (1978) showed you can extract this "risk-neutral density" by taking the second derivative of call prices with respect to strike. Horizon uses this to compare options-implied probabilities against prediction market prices - when they disagree, that's an edge signal.
</Tip>

# Breeden-Litzenberger

Horizon implements the Breeden-Litzenberger theorem to extract risk-neutral probability densities from options chains, then maps these to prediction market edge signals. All computation runs in Rust.

<CardGroup cols={2}>
  <Card title="Density Extraction" icon="chart-area">
    `risk_neutral_density()` - extract the full probability distribution from options prices via finite differences.
  </Card>
  <Card title="Probability Queries" icon="percent">
    `implied_probability_above()`, `below()`, `between()` - integrate the density over arbitrary ranges.
  </Card>
  <Card title="Edge Detection" icon="bullseye">
    `cross_asset_edge()` - compare options-implied probability against prediction market price.
  </Card>
  <Card title="Risk Premium" icon="scale-balanced">
    `risk_premium_adjustment()` - blend options and market probabilities to account for risk premium differences.
  </Card>
</CardGroup>

---

## How It Works

Given a set of call option prices C(K) across strikes K:

1. **Compute density**: `f(K) = e^{rT} * d²C/dK²` (Breeden-Litzenberger theorem)
2. **Normalize**: Scale so the density integrates to 1.0 via trapezoidal rule
3. **Integrate**: CDF = cumulative integral; probability queries integrate over ranges
4. **Compare**: If options say P(BTC > 100K) = 0.70 but the prediction market prices it at 0.55, that's a +0.15 edge

---

## Core Functions

### hz.risk_neutral_density

Extract the full risk-neutral probability density from an options chain.

```python
import horizon as hz

# Example: BTC options chain (calls)
strikes = [80000, 85000, 90000, 95000, 100000, 105000, 110000, 115000, 120000]
call_prices = [22000, 17500, 13500, 10000, 7200, 4800, 3000, 1700, 900]

rnd = hz.risk_neutral_density(
    strikes=[float(k) for k in strikes],
    call_prices=[float(c) for c in call_prices],
    r=0.05,    # Risk-free rate
    t=0.25,    # Time to expiry (in years)
)

print(f"Mean: ${rnd.mean:,.0f}")
print(f"Variance: {rnd.variance:,.0f}")
print(f"Density points: {len(rnd.densities)}")
print(f"CDF at last strike: {rnd.cdf[-1]:.4f}")  # Should be ~1.0
```

### RiskNeutralDensity Type

| Field | Type | Description |
|-------|------|-------------|
| `strikes` | `list[float]` | Strike prices |
| `densities` | `list[float]` | Probability density at each strike |
| `cdf` | `list[float]` | Cumulative distribution function |
| `mean` | `float` | Mean of the distribution |
| `variance` | `float` | Variance of the distribution |

---

## Probability Queries

### hz.implied_probability_above

Probability that the underlying exceeds a threshold.

```python
prob = hz.implied_probability_above(
    strikes=strikes_f,
    call_prices=calls_f,
    threshold=100000.0,    # BTC > $100K?
    r=0.05,
    t=0.25,
)
print(f"P(BTC > $100K) = {prob:.4f}")
```

### hz.implied_probability_below

Probability that the underlying is below a threshold.

```python
prob = hz.implied_probability_below(strikes_f, calls_f, 90000.0, r=0.05, t=0.25)
print(f"P(BTC < $90K) = {prob:.4f}")
```

### hz.implied_probability_between

Probability that the underlying falls within a range.

```python
prob = hz.implied_probability_between(
    strikes_f, calls_f,
    lower=95000.0,
    upper=110000.0,
    r=0.05,
    t=0.25,
)
print(f"P($95K < BTC < $110K) = {prob:.4f}")
```

---

## Edge Detection

### hz.cross_asset_edge

Compare an options-implied probability against a prediction market price.

```python
# Options say P(BTC > $100K) = 0.70
# Prediction market prices it at 0.55
edge = hz.cross_asset_edge(
    option_prob=0.70,
    market_price=0.55,
    transaction_cost=0.005,    # 50 bps round-trip
)
print(f"Raw edge: {edge.raw_edge:+.4f}")          # +0.1500
print(f"Adjusted edge: {edge.adjusted_edge:+.4f}") # +0.1450
print(f"Confidence: {edge.confidence:.4f}")         # High
```

### CrossAssetEdge Type

| Field | Type | Description |
|-------|------|-------------|
| `option_implied_prob` | `float` | Probability from options chain |
| `market_price` | `float` | Prediction market price |
| `raw_edge` | `float` | `option_prob - market_price` |
| `adjusted_edge` | `float` | Edge minus transaction costs |
| `confidence` | `float` | Edge magnitude relative to transaction cost (0-1) |

---

## Risk Premium Adjustment

### hz.risk_premium_adjustment

Options prices contain a risk premium that prediction markets don't. This function blends the two probability estimates using a historical calibration ratio.

```python
adjusted = hz.risk_premium_adjustment(
    option_prob=0.70,
    market_price=0.55,
    historical_ratio=0.6,  # 60% weight to options, 40% to market
)
print(f"Blended probability: {adjusted:.4f}")
# 0.70 * 0.6 + 0.55 * 0.4 = 0.64
```

| Parameter | Type | Description |
|-----------|------|-------------|
| `option_prob` | `float` | Options-implied probability |
| `market_price` | `float` | Prediction market price |
| `historical_ratio` | `float` | Weight on options probability (0-1, default 0.5) |

---

## Pipeline Integration

### hz.cross_asset_signal

Pipeline factory that reads options chain data from `ctx.params` and computes edge signals.

```python
hz.run(
    pipeline=[
        options_data_fetcher,  # Populates ctx.params["options_chain"]
        hz.cross_asset_signal(
            options_data_key="options_chain",
            threshold_key="threshold",
            fee_rate=0.005,
        ),
        my_strategy,  # Reads ctx.params["cross_asset_edge"]
    ],
    ...
)
```

Expects `ctx.params["options_chain"]` to be:
```python
{
    "strikes": [80000.0, 85000.0, ...],
    "call_prices": [22000.0, 17500.0, ...],
}
```

Injects into `ctx.params`:
```python
{
    "cross_asset_edge": {
        "option_implied_prob": 0.70,
        "market_price": 0.55,
        "raw_edge": 0.15,
        "adjusted_edge": 0.145,
        "confidence": 0.97,
    }
}
```

---

## Example: Cross-Asset Arb Strategy

```python
import horizon as hz

def options_fetcher(ctx):
    """Fetch BTC options chain (placeholder)."""
    ctx.params["options_chain"] = {
        "strikes": [80000, 85000, 90000, 95000, 100000, 105000, 110000],
        "call_prices": [22000, 17500, 13500, 10000, 7200, 4800, 3000],
    }
    ctx.params["threshold"] = 100000.0  # BTC > $100K
    ctx.params["r"] = 0.05
    ctx.params["t"] = 0.25

def edge_trader(ctx):
    """Trade when cross-asset edge exceeds threshold."""
    edge_data = ctx.params.get("cross_asset_edge")
    if edge_data and edge_data["adjusted_edge"] > 0.05:
        # Options say price should be higher -> buy YES
        return [hz.Quote(bid=edge_data["market_price"] + 0.01, ask=0.99, size=10.0)]
    return []

hz.run(
    pipeline=[
        options_fetcher,
        hz.cross_asset_signal("options_chain", "threshold", fee_rate=0.005),
        edge_trader,
    ],
    ...
)
```
