---
title: "Horizon Feeds"
description: "Live price data feeds for Horizon: Binance WebSocket, Polymarket orderbook, Kalshi orderbook, and REST."
icon: "rss"
---

Feeds provide live price data to your pipeline functions via `ctx.feeds`. Each feed runs as an async task on the engine's tokio runtime.

## Available Feeds

<CardGroup cols={2}>
  <Card title="BinanceWS" icon="bolt">
    Real-time trade stream from Binance WebSocket.
  </Card>
  <Card title="PolymarketBook" icon="book-open">
    Polymarket orderbook snapshots via WebSocket.
  </Card>
  <Card title="KalshiBook" icon="chart-bar">
    Kalshi orderbook polling via REST.
  </Card>
  <Card title="RESTFeed" icon="globe">
    Generic REST API polling for any endpoint.
  </Card>
</CardGroup>

## BinanceWS

Real-time price stream from Binance via WebSocket:

```python
hz.run(
    feeds={"btc": hz.BinanceWS("btcusdt")},
    ...
)

def fair_value(ctx: hz.Context) -> float:
    return ctx.feeds["btc"].price
```

The feed connects to Binance's trade stream and updates `price`, `bid`, `ask`, and `timestamp` on each trade.

| Field | Description |
|-------|-------------|
| `symbol` | Binance trading pair (e.g., `"btcusdt"`, `"ethusdt"`) |

## PolymarketBook

Polymarket orderbook feed via WebSocket:

```python
hz.run(
    feeds={"poly": hz.PolymarketBook("will-btc-hit-100k")},
    ...
)

def fair_value(ctx: hz.Context) -> float:
    poly = ctx.feeds["poly"]
    return (poly.bid + poly.ask) / 2
```

| Field | Description |
|-------|-------------|
| `market_slug` | Polymarket market slug |

## KalshiBook

Kalshi orderbook feed via REST polling:

```python
hz.run(
    feeds={"kalshi": hz.KalshiBook("KXBTC-25FEB16")},
    ...
)
```

| Field | Description |
|-------|-------------|
| `ticker` | Kalshi market ticker (e.g., `"KXBTC-25FEB16"`) |

## RESTFeed

Generic REST API polling feed for any JSON endpoint:

```python
hz.run(
    feeds={"custom": hz.RESTFeed("https://api.example.com/price", interval=5.0)},
    ...
)
```

| Field | Default | Description |
|-------|---------|-------------|
| `url` | required | REST endpoint URL |
| `interval` | `5.0` | Polling interval in seconds |

## Feed Data in Context

Each feed is accessible in pipeline functions via `ctx.feeds`:

```python
def fair_value(ctx: hz.Context) -> float:
    btc = ctx.feeds.get("btc", hz.context.FeedData())

    btc.price       # Last trade price
    btc.bid         # Best bid
    btc.ask         # Best ask
    btc.timestamp   # Unix timestamp of last update

    return btc.price
```

## FeedSnapshot (Engine Level)

At the Engine level, feed data is stored as `FeedSnapshot` objects:

```python
snap = engine.feed_snapshot("btc")

snap.price       # 100250.0
snap.bid         # 100248.0
snap.ask         # 100252.0
snap.timestamp   # 1700000000.0
snap.source      # "binance_ws"
snap.volume_24h  # 50000.0
```

Other Engine feed methods:

```python
all_snaps = engine.all_feed_snapshots()  # dict[str, FeedSnapshot]
age = engine.feed_age("btc")            # seconds since last update (or None)
engine.stop_feeds()                      # stop all feeds
```

## Feed Staleness

In live mode, the strategy loop checks feed staleness before quoting. If any feed is stale (no update within the threshold), quoting is skipped for that cycle:

```python
# Default threshold: 30 seconds
# Override via params:
hz.run(
    params={"feed_stale_threshold": 60.0},
    ...
)
```

The `FeedData.is_stale()` method checks staleness:

```python
feed = ctx.feeds.get("btc", hz.context.FeedData())
if feed.is_stale(max_age_secs=30.0):
    # Feed hasn't updated, skip quoting
    return []
```

## Engine-Level Feed Management

When using the Engine directly, start feeds with `start_feed()`:

```python
engine.start_feed("btc", "binance_ws", symbol="btcusdt")
engine.start_feed("poly", "polymarket_book", symbol="will-btc-hit-100k")
engine.start_feed("kalshi", "kalshi_book", symbol="KXBTC-25FEB16")
engine.start_feed("custom", "rest", url="https://api.example.com/price", interval=5.0)
```

## Multiple Feeds

Use multiple feeds to combine data sources:

```python
hz.run(
    feeds={
        "btc": hz.BinanceWS("btcusdt"),
        "poly": hz.PolymarketBook("will-btc-hit-100k"),
        "kalshi": hz.KalshiBook("KXBTC-25FEB16"),
    },
    ...
)

def fair_value(ctx: hz.Context) -> float:
    btc = ctx.feeds.get("btc", hz.context.FeedData())
    poly = ctx.feeds.get("poly", hz.context.FeedData())

    # Combine BTC spot price with Polymarket book
    if poly.bid > 0 and poly.ask > 0:
        return (poly.bid + poly.ask) / 2
    return btc.price * 0.01  # Fallback
```
