# prediction.click — AI Agent Skills

## What is prediction.click?

prediction.click is a real-time fair value engine for Polymarket's short-term crypto Up/Down markets.

**How it works:** Polymarket runs binary markets like "Will BTC be higher than $87,200 in 5 minutes?" with two tokens — UP and DOWN. Each trades at a price between $0 and $1 (representing 0–100% probability). prediction.click computes the mathematically correct probability using a pricing model and compares it to what the market is trading at. The difference is called **alpha** — and that's where the profit opportunity is.

### Core Concepts

**Fair Value** — The model-derived probability that the asset price will be above (UP) or below (DOWN) its starting price (strike) at expiry. Computed every 1 second using real-time Binance spot prices.

**Market Price** — The current trading price on Polymarket for the UP or DOWN token. Sourced from the Polymarket CLOB (Central Limit Order Book) in real-time.

**Alpha** — `(Fair Value / Market Price - 1) × 100`. Measures how much the market is underpriced relative to fair value as a percentage. For example, if fair value is 53% and market price is 49%, alpha = (0.53 / 0.49 - 1) × 100 = **8.16%**. Only positive alpha matters (negative means the market is overpriced). This is what the prediction.click chart displays.

**Strike** — The reference price at the start of the market window. If the asset closes above the strike at expiry, UP wins. If below, DOWN wins.

**Sigma (σ)** — Annualized volatility computed using EWMA (Exponentially Weighted Moving Average) on 1-minute candles with λ=0.94. Higher sigma = more uncertainty = fair values closer to 50%.

**Stale** — When `stale: true`, the pricing engine has outdated data (e.g., Binance feed interrupted). Do not trade on stale data.

### Pricing Model

```
FV_UP = 1 - StudentT_CDF(ln(K/S) / σ√T, df=7)
FV_DOWN = 1 - FV_UP
```

- **S** = current spot price (Binance aggTrade, ~100ms updates)
- **K** = strike price (asset price at market window start)
- **σ** = EWMA volatility from 1-minute candles (λ=0.94), annualized (×√525600)
- **T** = time to expiry in years
- **df=7** = Student-t degrees of freedom (fat tails for crypto — extreme moves happen more than Normal predicts)

**How variables affect fair value:**
- S > K (price went up) → FV_UP increases
- S < K (price went down) → FV_UP decreases
- T → 0 (near expiry) → FV becomes extreme (hard to reverse a move with little time left)
- σ ↑ (high volatility) → FV closer to 50% (anything can happen)

### Assets & Timeframes

| Assets | BTC, ETH, SOL, XRP, DOGE, BNB |
|--------|-------------------------------|
| Timeframes | 5m, 15m, 1h, 4h |
| Total markets | 24 (6 assets × 4 timeframes) |
| Each market has | UP token + DOWN token |
| Data sources | Binance (spot), Polymarket (market prices) |
| Fair value update | Every 1 second |
| Market price update | Real-time (Polymarket CLOB WebSocket) |

---

## API Reference

**Base URL:** `https://api.prediction.click`

**Authentication:** All requests require an API key:
```
Authorization: Bearer pk_YOUR_KEY
```

**How to get an API key:**

**Option A — User provides key (simplest):**
Ask the user to go to [prediction.click/api-keys](https://prediction.click/api-keys), connect wallet, buy credits, and paste the `pk_...` key to you.

**Option B — Programmatic (if you have wallet access):**
If you have access to a wallet with USDC on Base, you can self-provision a key via x402 payment. No browser or Privy auth needed.

```typescript
import { wrapFetchWithPayment } from "x402-fetch"

// maxValue = price in USDC base units (6 decimals) + $1 buffer
// beginner_20k = $1 → maxValue = 2_000_000 (price + buffer)
const maxValue = BigInt(2_000_000)
const paidFetch = wrapFetchWithPayment(fetch, walletClient, maxValue)
const res = await paidFetch(
  "https://api.prediction.click/api/credits/purchase?package=beginner_20k&wallet=0xYOUR_WALLET&network=base",
  { method: "POST" }
)
const { key, tier, credits } = await res.json()
// key = "pk_..." — use this for all subsequent API calls
```

**maxValue by package** (USDC has 6 decimals, add $1 buffer):
| Package | Price | maxValue |
|---------|-------|----------|
| `beginner_20k` | $1 | `BigInt(2_000_000)` |
| `basic_1m` | $30 | `BigInt(31_000_000)` |
| `basic_5m` | $140 | `BigInt(141_000_000)` |
| `pro_10m` | $200 | `BigInt(201_000_000)` |
| `pro_50m` | $900 | `BigInt(901_000_000)` |

This creates the API key and credits in one step. Minimum: $1 USDC for 20K requests.

**Error codes:**
- `401` — Missing or invalid API key
- `402` — Credits exhausted
- `404` — No data available for this asset/timeframe
- `429` — Rate limit exceeded
- `502` — External API (Binance/Polymarket) fetch failed
- `503` — Service unavailable

---

### GET /api/markets

Get all market data at once — fair values, market prices, and orderbook depth for every asset and timeframe. This is the most efficient starting point: one request returns all 24 markets.

```bash
curl https://api.prediction.click/api/markets \
  -H "Authorization: Bearer pk_YOUR_KEY"
```

**Response:**
```json
{
  "BTC": {
    "5m": {
      "fair": {
        "fair_up": 0.5321,
        "fair_down": 0.4679,
        "sigma": 0.42,
        "spot": 87250.50,
        "strike": 87200.00,
        "window_high": 87300.00,
        "window_low": 87150.00,
        "params": { "model": "StudentT", "nu": 7, "T": 0.0000095 },
        "stale": false,
        "expired": false,
        "updated_at": "2026-03-25T10:00:00.000Z"
      },
      "market": {
        "up_price": 0.49,
        "down_price": 0.51,
        "strike": 87200.00,
        "starts_at": "2026-03-25T09:55:00.000Z",
        "expires_at": "2026-03-25T10:00:00.000Z"
      },
      "depth": {
        "bidDepth": 1800,
        "askDepth": 48200,
        "updated_at": "2026-03-25T09:59:45.000Z"
      }
    },
    "15m": { ... },
    "1h": { ... },
    "4h": { ... }
  },
  "ETH": { ... },
  "SOL": { ... },
  "XRP": { ... },
  "DOGE": { ... },
  "BNB": { ... }
}
```

**How to find opportunities from this response:**
```
alpha_up  = (fair.fair_up  / market.up_price  - 1) * 100  // e.g., 8.16%
alpha_down = (fair.fair_down / market.down_price - 1) * 100
```
- Only positive alpha matters (negative = overpriced, skip)
- Skip markets where `fair.stale` is `true` or `fair.expired` is `true`
- `depth.bidDepth` / `depth.askDepth` = total $ on bid/ask side (liquidity check)

---

### GET /api/fair-value/:asset/:timeframe

Get detailed fair value and market data for a single market. Includes token IDs needed for placing trades on Polymarket.

**Path parameters:**
| Name | Values |
|------|--------|
| `asset` | `BTC`, `ETH`, `SOL`, `XRP`, `DOGE`, `BNB` (case-insensitive) |
| `timeframe` | `5m`, `15m`, `1h`, `4h` |

```bash
curl https://api.prediction.click/api/fair-value/BTC/5m \
  -H "Authorization: Bearer pk_YOUR_KEY"
```

**Response:**
```json
{
  "asset": "BTC",
  "timeframe": "5m",
  "fair_value_up": 0.5321,
  "fair_value_down": 0.4679,
  "market_price_up": 0.49,
  "market_price_down": 0.51,
  "edge_up": 0.0421,
  "edge_down": -0.0421,
  "sigma": 0.42,
  "spot": 87250.50,
  "strike": 87200.00,
  "window_high": 87300.00,
  "window_low": 87150.00,
  "model": "StudentT",
  "params": { "model": "StudentT", "nu": 7, "T": 0.0000095 },
  "stale": false,
  "expired": false,
  "timestamp": "2026-03-25T10:00:00.000Z",
  "starts_at": "2026-03-25T09:55:00.000Z",
  "expires_at": "2026-03-25T10:00:00.000Z",
  "slug": "btc-updown-5m-1773678300",
  "condition_id": "0x...",
  "token_id_up": "0x...",
  "token_id_down": "0x..."
}
```

**Key fields:**
- `fair_value_up` / `fair_value_down` — model-derived probabilities (sum to ~1.0)
- `edge_up` / `edge_down` — difference between fair value and market price. To get alpha %: `(fair_value / market_price - 1) * 100`
- `sigma` — annualized volatility
- `token_id_up` / `token_id_down` — Polymarket token IDs for placing orders
- `condition_id` — Polymarket condition ID
- `slug` — Polymarket market slug

---

### GET /api/spot/:asset

Get the current real-time spot price from Binance and recent 1-minute candle history (~500 candles, ~8 hours).

**Path parameters:**
| Name | Values |
|------|--------|
| `asset` | `BTC`, `ETH`, `SOL`, `XRP`, `DOGE`, `BNB` (case-insensitive) |

```bash
curl https://api.prediction.click/api/spot/BTC \
  -H "Authorization: Bearer pk_YOUR_KEY"
```

**Response:**
```json
{
  "asset": "BTC",
  "spot": 87250.50,
  "candles": [
    {
      "time": 1742900400,
      "open": 87100.00,
      "high": 87300.00,
      "low": 87050.00,
      "close": 87250.00
    },
    ...
  ]
}
```

**Fields:**
- `spot` — latest trade price from Binance (updates ~100ms)
- `candles` — 1-minute OHLC candles, `time` is unix timestamp in seconds

---

### GET /api/orderbook/:asset/:timeframe

Get the Polymarket CLOB orderbook (bids and asks) for a specific market side.

**Path parameters:**
| Name | Values |
|------|--------|
| `asset` | `BTC`, `ETH`, `SOL`, `XRP`, `DOGE`, `BNB` (case-insensitive) |
| `timeframe` | `5m`, `15m`, `1h`, `4h` |

**Query parameters:**
| Name | Values | Default | Description |
|------|--------|---------|-------------|
| `side` | `yes`, `no` | `yes` | `yes` = UP token, `no` = DOWN token |

```bash
curl "https://api.prediction.click/api/orderbook/ETH/1h?side=yes" \
  -H "Authorization: Bearer pk_YOUR_KEY"
```

**Response:**
```json
{
  "asset": "ETH",
  "timeframe": "1h",
  "side": "yes",
  "token_id": "0x...",
  "bids": [
    { "price": "0.49", "size": "1000" },
    { "price": "0.48", "size": "2500" },
    ...
  ],
  "asks": [
    { "price": "0.50", "size": "500" },
    { "price": "0.51", "size": "1200" },
    ...
  ]
}
```

**Notes:**
- Bids = buy orders (sorted high to low)
- Asks = sell orders (sorted low to high)
- `size` is in USDC
- Check both `?side=yes` (UP) and `?side=no` (DOWN) for full picture

---

### GET /api/opportunity/:asset/:timeframe

Find profitable fills by walking the orderbook. Compares each price level against fair value and returns fills with positive edge, including expected profit after Polymarket fees.

**Path parameters:**
| Name | Values |
|------|--------|
| `asset` | `BTC`, `ETH`, `SOL`, `XRP`, `DOGE`, `BNB` (case-insensitive) |
| `timeframe` | `5m`, `15m`, `1h`, `4h` |

```bash
curl https://api.prediction.click/api/opportunity/BTC/5m \
  -H "Authorization: Bearer pk_YOUR_KEY"
```

**Response:**
```json
{
  "asset": "BTC",
  "timeframe": "5m",
  "up": {
    "side": "UP",
    "total_size": 150.5,
    "total_cost": 72.24,
    "total_fee": 1.44,
    "expected_profit": 6.32,
    "fill_levels": 2,
    "fills": [
      { "price": 0.48, "size": 100, "profit": 3.86 },
      { "price": 0.49, "size": 50.5, "profit": 2.46 }
    ]
  },
  "down": {
    "side": "DOWN",
    "total_size": 0,
    "total_cost": 0,
    "total_fee": 0,
    "expected_profit": 0,
    "fill_levels": 0,
    "fills": []
  }
}
```

**How to read:**
- `fills` are sorted by price (cheapest first = best edge)
- `profit` per fill = `(fairValue - price) × size - fee`
- `expected_profit` = sum of all fill profits (fees already deducted)
- `total_cost` = total USDC needed to buy all fills
- Empty `fills` / zero `expected_profit` = no profitable fills on that side

---

### GET /api/history/:asset/:timeframe

Get historical fair value and market price data at 1-second granularity. Contains both live data (from pricing engine) and backfilled data (from 1-minute candles). History auto-expires: TTL = 2 × timeframe.

**Path parameters:**
| Name | Values |
|------|--------|
| `asset` | `BTC`, `ETH`, `SOL`, `XRP`, `DOGE`, `BNB` (case-insensitive) |
| `timeframe` | `5m`, `15m`, `1h`, `4h` |

**History TTL:**
| Timeframe | History retained |
|-----------|----------------|
| 5m | 10 minutes |
| 15m | 30 minutes |
| 1h | 2 hours |
| 4h | 8 hours |

```bash
curl https://api.prediction.click/api/history/BTC/5m \
  -H "Authorization: Bearer pk_YOUR_KEY"
```

**Response:**
```json
{
  "asset": "BTC",
  "timeframe": "5m",
  "count": 600,
  "backfill_count": 300,
  "live_count": 300,
  "points": [
    {
      "t": 1742900100000,
      "fu": 0.52,
      "fd": 0.48,
      "mu": 0.50,
      "md": 0.50
    },
    ...
  ]
}
```

**Fields per point:**
- `t` — timestamp in milliseconds
- `fu` — fair value UP (model probability)
- `fd` — fair value DOWN
- `mu` — market price UP (from Polymarket)
- `md` — market price DOWN (from Polymarket)

**Notes:**
- `backfill_count` points have 1-minute resolution (derived from Binance candles)
- `live_count` points have 1-second resolution (from pricing engine)
- Points are sorted chronologically (oldest first)

---

### GET /api/prediction-log

Get historical prediction results — actual outcomes of past markets. Useful for evaluating model accuracy. Returns all entries across all assets and timeframes (up to 200 per asset/timeframe combo). Filter by asset or timeframe client-side.

**Parameters:** none (returns everything, filter client-side)

```bash
curl https://api.prediction.click/api/prediction-log \
  -H "Authorization: Bearer pk_YOUR_KEY"
```

**Response:** Array of prediction log entries, sorted by `logged_at` descending:
```json
[
  {
    "asset": "BTC",
    "timeframe": "5m",
    "outcome": "UP",
    "strike": 87200.00,
    "final_spot": 87450.00,
    "fair_up": 0.52,
    "fair_down": 0.48,
    "market_up": 0.49,
    "market_down": 0.51,
    "sigma": 0.42,
    "spot": 87250.50,
    "starts_at": "2026-03-25T09:55:00.000Z",
    "expires_at": "2026-03-25T10:00:00.000Z",
    "snapshots": [...],
    "logged_at": "2026-03-25T10:00:05.000Z"
  },
  ...
]
```

**How to compute accuracy:**
- `outcome` = "UP" if `final_spot > strike`, "DOWN" if `final_spot < strike`
- Compare `outcome` against whether `fair_up > 0.5` (model predicted UP) or `fair_down > 0.5` (model predicted DOWN)
- Filter by asset/timeframe client-side to analyze specific combinations

---

### GET /api/health

Check the health status of all backend services.

```bash
curl https://api.prediction.click/api/health \
  -H "Authorization: Bearer pk_YOUR_KEY"
```

**Response (HTTP 200 if all healthy, 503 if any degraded/down):**
```json
{
  "price_daemon": {
    "status": "ok",
    "last_update": "2026-03-25T10:00:15.000Z",
    "details": "running normally"
  },
  "market_daemon": {
    "status": "ok",
    "last_update": "2026-03-25T10:00:14.000Z",
    "details": "running normally"
  },
  "pricing_engine": {
    "status": "ok",
    "last_update": "2026-03-25T10:00:15.000Z",
    "details": "running normally"
  },
  "redis": {
    "status": "connected"
  }
}
```

**Status values:**
- `ok` — running normally (last update < 60s ago)
- `degraded` — last update 60s–300s ago (data may be stale)
- `down` — last update > 300s ago or no data (do not trade)

---

## Skills

### Skill: Find the Best Trade Right Now

**When to use:** User asks "what should I trade?", "any good opportunities?", "where's the alpha?"

**Steps:**
1. `GET /api/markets` — fetch all 24 markets in one request
2. For each market, compute alpha:
   - `alpha_up = (fair.fair_up / market.up_price - 1) * 100`
   - `alpha_down = (fair.fair_down / market.down_price - 1) * 100`
   - Skip where `fair.stale == true` or `fair.expired == true`
   - Only consider positive alpha (negative = overpriced)
3. Rank by alpha, pick top 1-3
4. For each top pick, `GET /api/opportunity/:asset/:tf` to see exact fills and profit after fees
5. Present recommendation: asset, timeframe, side (UP/DOWN), alpha %, expected profit

**Example response:**
> Best opportunity: **BTC 5m UP** — 8.2% alpha. Fair value 53.2% vs market 49.0%. Expected profit $0.42 on a $10 order after fees.

---

### Skill: Deep Dive on a Specific Market

**When to use:** User asks about a specific asset/timeframe, e.g. "how's ETH 1h looking?"

**Steps:**
1. `GET /api/fair-value/ETH/1h` — fair value, sigma, strike, token IDs
2. `GET /api/orderbook/ETH/1h?side=yes` and `GET /api/orderbook/ETH/1h?side=no` — check liquidity on both sides
3. `GET /api/opportunity/ETH/1h` — find profitable fills
4. Optionally `GET /api/spot/ETH` — current Binance price and recent candle trend

**What to report:**
- Fair value UP vs DOWN (should sum to ~100%)
- Edge on each side (positive = underpriced = buying opportunity)
- Orderbook depth (thin book = harder to fill, higher slippage)
- Volatility (sigma) — higher = more uncertainty = fair values closer to 50%
- Time to expiry — closer to expiry = model is more decisive (FV further from 50%)

---

### Skill: Monitor Multiple Markets

**When to use:** User wants ongoing monitoring, e.g. "watch BTC and ETH for me"

**Steps:**
1. `GET /api/markets` periodically (e.g., every 30–60 seconds)
2. Compute alpha, compare with previous check
3. Alert when alpha exceeds a threshold (e.g., > 5%)
4. Note when markets rotate — 5m markets expire every 5 minutes, new ones appear immediately

---

### Skill: Analyze Price History

**When to use:** User asks "how has fair value tracked the market?", "show me the trend"

**Steps:**
1. `GET /api/history/:asset/:tf` — 1-second granularity data
2. Compare `fu` (fair value UP) vs `mu` (market price UP) over time
3. Identify periods where alpha was consistently large — persistent mispricing
4. Note convergence/divergence patterns near expiry

---

### Skill: Evaluate Model Accuracy

**When to use:** User asks "how accurate is this?", "what's the win rate?"

**Steps:**
1. `GET /api/prediction-log` — get all historical outcomes
2. Filter by asset/timeframe as needed
3. For each entry: model predicted UP if `fair_up > 0.5`, actual was `outcome`
4. Compute win rate = correct predictions / total predictions
5. Break down by asset and timeframe to find strongest performers

---

### Skill: Check System Health

**When to use:** Before trading, if data looks off, or user reports issues

**Steps:**
1. `GET /api/health`
2. All services should show `status: "ok"`
3. If any service is `degraded` or `down`, warn the user — data may be unreliable, do not trade

---

### Skill: Pre-Trade Checklist

**When to use:** Before recommending any trade

1. **Health** — `GET /api/health` → all services `ok`?
2. **Stale** — Is `stale: false` for this market? Skip if stale.
3. **Alpha size** — Is alpha > 5%? Smaller alpha may not survive fees.
4. **Liquidity** — `GET /api/orderbook/:asset/:tf` → enough size at the target price?
5. **Time to expiry** — Too close to expiry? Order may not fill in time.
6. **Fees** — Polymarket charges fees. `/api/opportunity` accounts for this in expected profit.

---

### Skill: Execute a Trade on Polymarket

**When to use:** User wants to actually buy/sell based on an opportunity, or is building a trading bot.

prediction.click provides the **signals** (fair value, alpha, token IDs). To execute trades, read the official Polymarket skill for CLOB API setup, authentication, and order placement:

> **Read: https://raw.githubusercontent.com/Polymarket/agent-skills/refs/heads/main/SKILL.md**

**Requirements:**
- The user must have a Polymarket account that can trade. Ask the user to verify: go to [polymarket.com](https://polymarket.com), connect their wallet, deposit funds, and buy any $1 position. If that works, the wallet is ready (Safe deployed, approvals set, TOS signed).
- Once verified, the agent can use the wallet's EOA private key to derive Polymarket API credentials via `ClobClient.createOrDeriveApiKey()` and trade programmatically. The EOA signs orders, but funds live in the derived Gnosis Safe address (set as `funder` in the CLOB client).

**Workflow: prediction.click signals → Polymarket execution**

```
1. GET /api/health → verify system is healthy
2. GET /api/markets → scan all 24 markets for alpha
3. Filter: alpha > 5%, not stale, not expired
4. GET /api/opportunity/:asset/:tf → get exact fill prices after fees
5. GET /api/fair-value/:asset/:tf → get token_id_up / token_id_down
6. Place order on Polymarket CLOB with the token ID (see Polymarket skill above)
7. Repeat on interval (e.g., every 30s for 5m markets)
```

**What you get from our API:**
```bash
curl https://api.prediction.click/api/fair-value/BTC/5m \
  -H "Authorization: Bearer pk_YOUR_KEY"

# Response includes:
# "token_id_up": "0x...",   ← pass to Polymarket CLOB to buy UP
# "token_id_down": "0x...", ← pass to Polymarket CLOB to buy DOWN
# "edge_up": 0.0421         ← alpha = (0.5321 / 0.49 - 1) * 100 = 8.6%
```

**Important notes:**
- **Price range:** 0 < price < 1 (probability). Never set price to 0 or 1.
- **Markets expire:** 5m markets rotate every 5 minutes. Check `expires_at` before ordering.
- **Stale data:** Never trade when `stale: true` — fair value may be wrong.
- **Fees:** Polymarket charges fees. `/api/opportunity` already accounts for fees in expected profit.

---

### Skill: Explain Fair Value & Edge

**When to use:** User asks "how does this work?", "what is alpha?"

Explain using the concepts from the top of this document. Key points:
- Fair value is a mathematical probability, not a guess
- Alpha = `(Fair Value / Market Price - 1) × 100` — measures how underpriced the market is relative to the model
- Student-t distribution captures crypto's fat tails (extreme moves happen more often than Normal predicts)
- EWMA volatility adapts quickly to recent market conditions
- Near expiry, fair value becomes more extreme (less time for reversals)
- High volatility pushes fair value toward 50% (anything can happen)

---

## API Access & Pricing

| Tier | Rate Limit | Cost per 1M requests | Min Deposit |
|------|-----------|---------------------|-------------|
| Beginner | 3 req/s | $50 | $1 USDC |
| Basic | 10 req/s | $30 | $30 USDC |
| Pro | 50 req/s | $20 | $100 USDC |

**Credit packages:**
| Package | Credits | Price (USDC) | $/1M | Tier |
|---------|---------|-------------|------|------|
| `beginner_20k` | 20,000 | $1 | $50 | Beginner |
| `basic_1m` | 1,000,000 | $30 | $30 | Basic |
| `basic_5m` | 5,000,000 | $140 | $28 | Basic |
| `pro_10m` | 10,000,000 | $200 | $20 | Pro |
| `pro_50m` | 50,000,000 | $900 | $18 | Pro |

**Purchase credits programmatically (x402):**
```typescript
import { wrapFetchWithPayment } from "x402-fetch"

// maxValue: price in USDC base units (6 decimals) + $1 buffer
const maxValue = BigInt(31_000_000) // $30 + $1 buffer for basic_1m
const paidFetch = wrapFetchWithPayment(fetch, walletClient, maxValue)

const res = await paidFetch(
  "https://api.prediction.click/api/credits/purchase?package=basic_1m&wallet=0xYOUR_WALLET&network=base",
  { method: "POST" }
)
const { key, tier, credits } = await res.json()
```

**Supported network:** Base (USDC only)
