Skip to main content

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.
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.

Overview

Reward Markets

hz.fetch_reward_markets() - fetch all reward-eligible markets from Polymarket.

Order Scoring

engine.check_order_scoring() - check if a specific order qualifies for rewards.

Rewards Tracker

hz.RewardsTracker - track maker fills and estimate rebates with deduplication.

Pipeline

hz.rewards_tracker() - pipeline function for automatic reward tracking in hz.run().

Fetching Reward Markets

Fetch all markets currently eligible for liquidity rewards (unauthenticated).
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

FieldTypeDescription
market_idstrMarket/condition identifier
condition_idstrPolymarket condition ID
questionstrMarket question text
rewards`RewardConfigNone`Reward parameters if eligible

RewardConfig Fields

FieldTypeDescription
max_spreadfloatMaximum allowed spread to qualify
min_sizefloatMinimum order size to qualify
ratesstrRaw JSON of rate tiers from the API

Checking Order Scoring

Check if a live order qualifies for rewards (authenticated, Polymarket only).
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.
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

FieldTypeDescription
market_idstrMarket identifier
fills_scoredintNumber of qualifying fills
estimated_usdcfloatEstimated rebate USDC
total_notionalfloatTotal notional volume

Pipeline Function

The hz.rewards_tracker() pipeline function automatically tracks fills from the engine during hz.run().
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

ParameterTypeDefaultDescription
rebate_ratefloat0.0002Rebate as fraction of notional (2bps)
check_scoringboolFalseCall engine.check_order_scoring() per fill

Pipeline Output

The pipeline function returns a dict each cycle:
{
    "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,
}
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.