---
title: "Rewards Tracker"
description: "Track Polymarket liquidity rewards: fetch eligible markets, check order scoring, and estimate rebate earnings."
icon: "coins"
---

# Rewards Tracker

Horizon provides tools to track and estimate Polymarket liquidity rewards. Market makers earn USDC rebates on qualifying orders. The rewards module fetches eligible markets, checks order scoring status, and estimates earnings from fill data.

<Note>
  Polymarket pays liquidity rewards daily as USDC. There is no historical rewards API, so Horizon estimates earnings locally from fill data at a configurable rebate rate.
</Note>

## Overview

<CardGroup cols={2}>
  <Card title="Reward Markets" icon="list-check">
    `hz.fetch_reward_markets()` - fetch all reward-eligible markets from Polymarket.
  </Card>
  <Card title="Order Scoring" icon="star">
    `engine.check_order_scoring()` - check if a specific order qualifies for rewards.
  </Card>
  <Card title="Rewards Tracker" icon="chart-line-up">
    `hz.RewardsTracker` - track maker fills and estimate rebates with deduplication.
  </Card>
  <Card title="Pipeline" icon="pipe-section">
    `hz.rewards_tracker()` - pipeline function for automatic reward tracking in hz.run().
  </Card>
</CardGroup>

---

## Fetching Reward Markets

Fetch all markets currently eligible for liquidity rewards (unauthenticated).

```python
import horizon as hz

markets = hz.fetch_reward_markets()
for m in markets[:5]:
    print(f"{m.question}")
    if m.rewards:
        print(f"  max_spread={m.rewards.max_spread}, min_size={m.rewards.min_size}")
```

### RewardMarket Fields

| Field | Type | Description |
|-------|------|-------------|
| `market_id` | `str` | Market/condition identifier |
| `condition_id` | `str` | Polymarket condition ID |
| `question` | `str` | Market question text |
| `rewards` | `RewardConfig | None` | Reward parameters if eligible |

### RewardConfig Fields

| Field | Type | Description |
|-------|------|-------------|
| `max_spread` | `float` | Maximum allowed spread to qualify |
| `min_size` | `float` | Minimum order size to qualify |
| `rates` | `str` | Raw JSON of rate tiers from the API |

---

## Checking Order Scoring

Check if a live order qualifies for rewards (authenticated, Polymarket only).

```python
engine = hz.Engine(exchange="polymarket", ...)
scoring = engine.check_order_scoring("order-id-123")
print(f"Order qualifies for rewards: {scoring}")
```

Returns `False` for non-Polymarket exchanges.

---

## RewardsTracker Class

Track maker fills and estimate rebates locally.

```python
from horizon import RewardsTracker

tracker = RewardsTracker(rebate_rate=0.0002)  # 2bps

# Record fills as they come in
rebate = tracker.record_fill(
    market_id="0x123...",
    fill_id="fill-001",
    notional=10000.0,  # price * size
    is_maker=True,
    scoring=True,
)
print(f"Rebate: \${rebate:.2f}")  # $2.00

# Check totals
print(f"Total USDC earned: \${tracker.total_usdc:.2f}")
print(f"Markets: {len(tracker.epoch_rewards)}")

# Reset for new epoch
old_epoch = tracker.reset_epoch()
```

### Features

- **Deduplication**: duplicate fill IDs are automatically rejected
- **Per-market tracking**: separate `EpochRewards` per market
- **Epoch reset**: clear per-market accumulators while preserving lifetime totals
- **Configurable rate**: default 2bps, adjustable via `rebate_rate`

### EpochRewards Fields

| Field | Type | Description |
|-------|------|-------------|
| `market_id` | `str` | Market identifier |
| `fills_scored` | `int` | Number of qualifying fills |
| `estimated_usdc` | `float` | Estimated rebate USDC |
| `total_notional` | `float` | Total notional volume |

---

## Pipeline Function

The `hz.rewards_tracker()` pipeline function automatically tracks fills from the engine during `hz.run()`.

```python
import horizon as hz

def model(ctx):
    fair = ctx.feeds["poly"].price
    return hz.quotes(fair=fair, spread=0.04, size=10)

hz.run(
    pipeline=[
        model,
        hz.rewards_tracker(rebate_rate=0.0002),
    ],
    feeds={"poly": hz.PolymarketBook(token_id="0x123...")},
    markets=[hz.Market(id="0x123...", name="Example")],
    exchange="polymarket",
)
```

### Parameters

| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `rebate_rate` | `float` | `0.0002` | Rebate as fraction of notional (2bps) |
| `check_scoring` | `bool` | `False` | Call engine.check_order_scoring() per fill |

### Pipeline Output

The pipeline function returns a dict each cycle:

```python
{
    "epoch_rewards": {
        "market_id": {
            "market_id": "0x123...",
            "fills_scored": 42,
            "estimated_usdc": 8.40,
            "total_notional": 42000.0,
        }
    },
    "total_usdc": 8.40,
    "reward_markets_count": 1,
}
```

<Warning>
  Setting `check_scoring=True` makes an authenticated API call per fill, which adds latency. Only enable this for low-frequency strategies or when precise scoring data is needed.
</Warning>
