Skip to main content
Use live data feeds from ESPN (sports), NWS (weather), and Chainlink (on-chain oracles) to price prediction markets with real-world data.

ESPN Sports Feed

Trade NBA game outcome markets using live ESPN scoreboard data:
"""NBA game market maker using ESPN live scores."""

import horizon as hz
from horizon.context import FeedData


def fair_value(ctx: hz.Context) -> float:
    """Estimate win probability from live score."""
    espn = ctx.feeds.get("nba_game", FeedData())

    if espn.price <= 0:
        return 0.50  # no data yet

    # ESPN feed price = home team win probability estimate
    # based on score differential and time remaining
    return espn.price


def quoter(ctx: hz.Context, fair: float) -> list[hz.Quote]:
    """Quote around ESPN-derived fair value."""
    return hz.quotes(fair, spread=0.06, size=5)


hz.run(
    name="nba_mm",
    markets=["lakers-celtics-game-1"],
    feeds={
        "nba_game": hz.ESPNFeed(
            sport="basketball",
            league="nba",
            event_id="401656789",
            poll_interval=30,     # poll every 30 seconds
        ),
    },
    pipeline=[fair_value, quoter],
    risk=hz.Risk(max_position=50, max_drawdown_pct=5),
    interval=5.0,
    mode="paper",
)

NWS Weather Feed

Trade weather prediction markets using National Weather Service forecasts and alerts:
"""Weather market maker using NWS forecast data."""

import horizon as hz
from horizon.context import FeedData


def fair_value(ctx: hz.Context) -> float:
    """Estimate rain probability from NWS forecast."""
    weather = ctx.feeds.get("weather", FeedData())

    if weather.price <= 0:
        return 0.50

    # NWS feed price = precipitation probability from forecast
    return weather.price


def quoter(ctx: hz.Context, fair: float) -> list[hz.Quote]:
    """Wide spread for weather markets (high uncertainty)."""
    return hz.quotes(fair, spread=0.08, size=3)


hz.run(
    name="weather_mm",
    markets=["rain-nyc-tomorrow"],
    feeds={
        "weather": hz.NWSFeed(
            latitude=40.7128,
            longitude=-74.0060,      # New York City
            poll_interval=300,        # poll every 5 minutes
            include_alerts=True,
        ),
    },
    pipeline=[fair_value, quoter],
    risk=hz.Risk(max_position=30, max_drawdown_pct=3),
    interval=10.0,
    mode="paper",
)
Use Chainlink price feeds as an on-chain data source for crypto prediction markets:
"""Chainlink oracle feed for BTC price markets."""

import horizon as hz
from horizon.context import FeedData


def fair_value(ctx: hz.Context) -> float:
    """Price a BTC > $100k market using Chainlink oracle."""
    chainlink = ctx.feeds.get("btc_oracle", FeedData())

    if chainlink.price <= 0:
        return 0.50

    # Simple proximity model: how close is BTC to $100k?
    btc_price = chainlink.price
    distance = (btc_price - 100_000) / 100_000

    # Sigmoid-like mapping
    import math
    fair = 1.0 / (1.0 + math.exp(-distance * 10))
    return max(0.05, min(0.95, fair))


def quoter(ctx: hz.Context, fair: float) -> list[hz.Quote]:
    return hz.quotes(fair, spread=0.04, size=5)


hz.run(
    name="chainlink_mm",
    markets=["btc-100k"],
    feeds={
        "btc_oracle": hz.ChainlinkFeed(
            contract_address="0x5f4eC3Df9cbd43714FE2740f5E3616155c5b8419",  # ETH mainnet BTC/USD
            rpc_url="https://eth-mainnet.g.alchemy.com/v2/YOUR_API_KEY",
            poll_interval=60,       # poll every 60 seconds
        ),
    },
    pipeline=[fair_value, quoter],
    risk=hz.Risk(max_position=50, max_drawdown_pct=5),
    interval=5.0,
    mode="paper",
)

How It Works

  1. ESPNFeed polls the ESPN API for live game data (scores, time remaining, game status) and converts it to a FeedSnapshot with price representing win probability
  2. NWSFeed fetches NWS point forecasts and active alerts, providing precipitation probability as the feed price
  3. ChainlinkFeed reads on-chain price oracles via JSON-RPC eth_call, providing decentralized price data

Combined Example

Use multiple real-world feeds together:
hz.run(
    name="multi_feed_mm",
    markets=["lakers-win", "rain-nyc", "btc-100k"],
    feeds={
        "nba_game": hz.ESPNFeed(sport="basketball", league="nba", event_id="401656789"),
        "weather": hz.NWSFeed(latitude=40.7128, longitude=-74.0060),
        "btc": hz.ChainlinkFeed(
            contract_address="0x5f4eC3Df9cbd43714FE2740f5E3616155c5b8419",
            rpc_url="https://eth-mainnet.g.alchemy.com/v2/YOUR_API_KEY",
        ),
    },
    pipeline=[fair_value, quoter],
    risk=hz.Risk(max_position=50),
    interval=5.0,
    mode="paper",
)

Run It

python examples/sports_weather_feeds.py
See Feeds for the full feed reference.