---
title: "Horizon GLFT Market Maker"
description: "Full pipeline: Black-Scholes binary pricing, spread-based toxicity, GLFT adverse selection spread."
icon: "chart-line"
---

A market maker on Polymarket using **Black-Scholes binary pricing**, **spread-based toxicity estimation**, and **GLFT adverse selection spread** with inventory skew.

## Full Code

```python
"""GLFT Market Maker on Polymarket (paper mode)."""

import math
import horizon as hz
from horizon.context import FeedData


def black_scholes_binary(price: float, strike: float, vol: float, tte: float) -> float:
    """Binary option fair value: Phi(d2)."""
    if tte <= 0:
        return 1.0 if price >= strike else 0.0
    d2 = (math.log(price / strike) - 0.5 * vol**2 * tte) / (vol * math.sqrt(tte))
    return 0.5 * (1 + math.erf(d2 / math.sqrt(2)))


def spread_toxicity(bid: float, ask: float) -> float:
    """Spread-based toxicity proxy: wider spread = more toxic flow."""
    if bid <= 0 or ask <= 0:
        return 0.5
    mid = (bid + ask) / 2.0
    if mid <= 0:
        return 0.5
    relative_spread = (ask - bid) / mid
    return min(1.0, max(0.0, relative_spread * 100.0))


def glft_spread(fair: float, tox: float, inventory: float, gamma: float = 0.1) -> float:
    """GLFT adverse selection spread with inventory penalty."""
    base = 0.02
    inv_penalty = gamma * abs(inventory) * 0.001
    tox_adj = tox * 0.04
    return base + inv_penalty + tox_adj


# --- Pipeline functions ---

def fair_value(ctx: hz.Context) -> float:
    btc_price = ctx.feeds.get("btc", FeedData()).price or 100_000
    strike = 100_000
    vol = 0.6
    tte = 30 / 365  # 30 days to expiry
    return black_scholes_binary(btc_price, strike, vol, tte)


def toxicity(ctx: hz.Context) -> float:
    feed = ctx.feeds.get("btc", FeedData())
    return spread_toxicity(feed.bid, feed.ask)


def quoter(ctx: hz.Context, fair: float, tox: float) -> list[hz.Quote]:
    spread = glft_spread(fair, tox, ctx.inventory.net, gamma=0.1)
    return hz.quotes(fair, spread, size=5)


if __name__ == "__main__":
    hz.run(
        name="btc_mm",
        exchange=hz.Polymarket(private_key="0x_demo_key"),
        markets=["will-btc-hit-100k-by-end-of-2025"],
        feeds={"btc": hz.BinanceWS("btcusdt")},
        pipeline=[fair_value, toxicity, quoter],
        risk=hz.Risk(max_position=100, max_drawdown_pct=5),
        interval=0.5,
        mode="paper",
        dashboard=False,
    )
```

## Pipeline Breakdown

### Stage 1: Fair Value

Uses the **Black-Scholes binary option formula** to price a prediction market as a digital option:

```
P(binary) = Φ(d₂)

where d₂ = (ln(S/K) - 0.5σ²T) / (σ√T)
```

- `S` = current BTC price (from Binance feed)
- `K` = strike price ($100k)
- `σ` = implied volatility (0.6)
- `T` = time to expiry (30/365 years)

### Stage 2: Toxicity

Uses **spread-based toxicity** as a proxy for informed flow. A wider bid-ask spread on the underlying suggests more adverse selection:

- Tight spread → low toxicity → tighter quotes
- Wide spread → high toxicity → wider quotes

### Stage 3: Quoter

The **GLFT spread** combines three components:

```
spread = base_spread + γ × |inventory| × 0.001 + toxicity × 0.04
```

- **Base spread**: minimum spread (2 cents)
- **Inventory penalty**: widens spread as position grows
- **Toxicity adjustment**: widens spread when flow is more informed

## Run It

```bash
# Paper mode (default)
python examples/polymarket_mm.py

# Live mode
python -m horizon run examples/polymarket_mm.py --mode=live --dashboard
```
