In prediction markets, information is power but knowing who is betting is often more valuable than knowing what is being bet. While the Polymarket leaderboard shows you the top earners, it doesn’t give you the real-time insights needed to replicate their success before the odds shift.
Imagine getting an alert the moment a “whale” opens a massive position in a niche market, or automatically tracking the portfolio of a trader with a 90% win rate. Because Polymarket is built on the Polygon blockchain, this data is public, you just need the right tools to harvest it.
In this guide, we’ll walk through how to build a custom Polymarket wallet tracker using the public API. We will cover how to fetch user positions, filter for high-value trades, and build a Python script that helps you trade alongside the “smart money.”
Understanding Polymarket’s Architecture
Polymarket operates on Polygon (formerly Matic), a layer-2 Ethereum scaling solution. All trades are executed through a Central Limit Order Book (CLOB) system, but the data is queryable through two main interfaces: the CLOB API (for trading) and the Data API (for history and analytics).
Crucial Note: Users on Polymarket do not trade directly from their MetaMask/EOA address. Instead, they use a Proxy Wallet (often a Gnosis Safe) created by Polymarket. When tracking a user, you must use their Proxy Address (visible in their profile URL), or you will see zero trades.
Prerequisites
You’ll need Python 3.8 or higher and basic familiarity with REST APIs. Install the required dependencies:
Bash
pip install requests pandas python-dotenv
Core API Endpoints
We will use these key endpoints for our tracker:
- Trades Endpoint:
https://data-api.polymarket.com/trades— Returns complete trade history (Maker + Taker). - Activity Endpoint:
https://data-api.polymarket.com/activity— Captures redemptions (when a user claims winnings), which is vital for accurate P&L. - Gamma Endpoint:
https://gamma-api.polymarket.com/markets— Provides market metadata like “Yes/No” resolution status.
Building the Basic Tracker
We will create a class that handles the API connections. Note that we use the Data API for trades because it simplifies pagination and captures all trade types.
Python
import requests
import pandas as pd
import time
class PolymarketWalletTracker:
def __init__(self):
self.data_url = "https://data-api.polymarket.com"
self.gamma_url = "https://gamma-api.polymarket.com"
def get_trades(self, wallet_address):
"""
Fetch ALL trade history (Maker + Taker) handling pagination.
The Data API limits responses to 100 trades per call, so we loop
until no more data is returned.
"""
all_trades = []
offset = 0
limit = 100
while True:
endpoint = f"{self.data_url}/trades"
params = {
'user': wallet_address,
'limit': limit,
'offset': offset
}
try:
resp = requests.get(endpoint, params=params)
resp.raise_for_status()
data = resp.json()
# If list is empty, we have reached the end
if not data:
break
all_trades.extend(data)
# If we received fewer items than the limit, it's the last page
if len(data) < limit:
break
offset += limit
# Be kind to the API
time.sleep(0.1)
except Exception as e:
print(f"Error fetching trades: {e}")
break
return all_trades
def get_activity(self, wallet_address):
"""Fetch redemption and settlement activity"""
endpoint = f"{self.data_url}/activity"
params = {'user': wallet_address}
try:
response = requests.get(endpoint, params=params)
response.raise_for_status()
return response.json()
except Exception as e:
print(f"Error fetching activity: {e}")
return []
Calculating Position and P&L
The challenge in tracking wallets is calculating “Net Cash Flow.” We track how much USDC left the wallet (Buys) versus how much returned (Sells + Redemptions).
Python
def calculate_pnl(self, wallet_address):
"""Calculate comprehensive P&L for a wallet"""
trades = self.get_trades(wallet_address)
activity = self.get_activity(wallet_address)
positions = {}
total_invested = 0 # Cash flowing OUT (Buying)
total_returned = 0 # Cash flowing IN (Selling + Redeeming)
# 1. Process Trades
for trade in trades:
# Handle potential key variations between API versions
token_id = trade.get('asset_id') or trade.get('asset')
side = trade['side'] # 'BUY' or 'SELL'
size = float(trade['size'])
price = float(trade['price'])
cost = size * price
if token_id not in positions:
positions[token_id] = {
'quantity': 0,
'cost_basis': 0,
'market_id': trade.get('market')
}
if side == 'BUY':
positions[token_id]['quantity'] += size
positions[token_id]['cost_basis'] += cost
total_invested += cost
else: # SELL
positions[token_id]['quantity'] -= size
positions[token_id]['cost_basis'] -= cost
total_returned += cost
# 2. Process Redemptions (Winnings)
for event in activity:
if event['type'] == 'redeem':
# Redemption value is often stored in 'amount' or 'value'
val = float(event.get('value', 0) or event.get('amount', 0))
total_returned += val
# Net Profit = (Money Out) - (Money In)
realized_pnl = total_returned - total_invested
return {
'total_invested': total_invested,
'total_returned': total_returned,
'realized_pnl': realized_pnl,
'positions': positions
}
Handling Market Status & Real-Time Prices
To calculate Unrealized P&L (the value of tokens still held), we need live prices. The Gamma API is the easiest way to fetch this data.
Python
def get_market_price(self, market_id, token_id):
"""Get latest mid-market price from Gamma API"""
endpoint = f"{self.gamma_url}/markets/{market_id}"
try:
resp = requests.get(endpoint)
data = resp.json()
# Gamma returns a list of outcomes (tokens); find the one matching our token_id
if 'tokens' in data:
for token in data['tokens']:
if token.get('tokenId') == token_id:
return float(token.get('price', 0))
return 0
except:
return 0
Building a Complete Dashboard
Finally, we combine everything to generate a report. This function iterates through open positions, fetches their current value, and summarizes the wallet’s performance.
Python
def generate_wallet_report(self, wallet_address):
"""Generate complete wallet performance report"""
pnl_data = self.calculate_pnl(wallet_address)
unrealized_value = 0
active_positions = 0
print(f"Analyzing wallet: {wallet_address}...")
for token_id, position in pnl_data['positions'].items():
# Only check price if we still hold the position
if position['quantity'] > 0.1: # Filter out dust
market_id = position['market_id']
current_price = self.get_market_price(market_id, token_id)
position_value = position['quantity'] * current_price
unrealized_value += position_value
active_positions += 1
total_equity = pnl_data['realized_pnl'] + unrealized_value
return {
'wallet': wallet_address,
'realized_pnl': round(pnl_data['realized_pnl'], 2),
'open_positions_value': round(unrealized_value, 2),
'total_account_value': round(total_equity, 2),
'active_bet_count': active_positions
}
Rate Limiting and Best Practices
Polymarket’s API is robust but has rate limits. If you plan to track multiple wallets:
- Cache Prices: Market prices don’t change every millisecond. Cache price results for 15-30 seconds to reduce API calls.
- Database Storage: For production systems, save trade history to a local database (like SQLite or PostgreSQL) so you only need to fetch new trades on subsequent updates.
- Error Handling: Always wrap network requests in
try/exceptblocks to prevent a single timeout from crashing your entire tracker.
Testing Your Tracker
Start by tracking well-known public wallets from the leaderboard. Cross-reference your calculated P&L with their public profile stats. If you see a discrepancy, check if you are missing “Redemption” events, as this is the most common source of error in P&L calculations.
How to Use the Polymarket API with Python (Step by Step)
This tutorial provides a visual guide to setting up your Python environment and making your first requests to the Polymarket API, effectively supplementing the code in this article.

