All articles
Guides

How to Monitor Smart Money Flows on Polymarket: a DIY Tutorial

Build your own smart money monitor with the public Polymarket API: pull trades, track positions, stream fills over WebSocket. Then see where DIY breaks: P&L, NegRisk, farmers.

August 20, 20264 min readOrcaLayer

Last updated: August 2026.

You can build a working smart money monitor on Polymarket with nothing but the public API and about fifty lines of Python. This tutorial walks through the real endpoints first, then is honest about where the DIY approach stops working and what it takes to fix it.

Step 1: pull recent trades from the public Data API

Polymarket's Data API is public and needs no key. One GET returns the latest fills across all markets:

curl "https://data-api.polymarket.com/trades?limit=100"

Each row carries the wallet (proxyWallet), the side (BUY or SELL), the outcome token (asset), the market (conditionId and title), size, price and a Unix timestamp. Filtering for size is one line:

import requests

trades = requests.get(
    "https://data-api.polymarket.com/trades",
    params={"limit": 500},
    timeout=30,
).json()

big = [t for t in trades if t["size"] * t["price"] >= 500]
for t in big:
    print(f'{t["proxyWallet"][:10]} {t["side"]} ${t["size"] * t["price"]:,.0f} '
          f'@ {t["price"]} in {t["title"][:50]}')

That already surfaces every trade of 500 dollars or more, minutes after it lands.

Step 2: track what a wallet holds, not just what it trades

A single fill tells you little. Conviction sits in accumulated positions, and a wallet that does not want to print one large fill can split the order into fifty small ones. The /positions endpoint aggregates per wallet:

curl "https://data-api.polymarket.com/positions?user=0xYOUR_TARGET_WALLET"

Rows carry conditionId, size, avgPrice and the current value, so a 700,000 dollar stake built from dust-sized fills still shows up as one line. Poll it for a watchlist of wallets on a cron and diff the snapshots: new positions and size changes are your flow signal.

Step 3: go live with the WebSocket stream

Polling has a floor of a minute or two. For live coverage Polymarket runs a public real-time stream; subscribe to the activity topic and every trade arrives as it settles:

import asyncio, json, websockets

async def main():
    async with websockets.connect("wss://ws-live-data.polymarket.com") as ws:
        await ws.send(json.dumps({
            "action": "subscribe",
            "subscriptions": [{"topic": "activity", "type": "trades"}],
        }))
        async for raw in ws:
            msg = json.loads(raw)
            print(msg)

asyncio.run(main())

In practice you will also need reconnect logic with backoff, an application-level ping, and a watchdog that forces a reconnect when messages stop flowing while the socket still looks open. Silent stalls are the normal failure mode of this stream, not the exception.

Step 4: decide which wallets are actually smart

This is where the tutorial stops being easy. "Big" is not "smart": size tells you a wallet moves money, not that it wins. To rank wallets you need each one's history:

curl "https://data-api.polymarket.com/activity?user=0xWALLET&limit=500"

Then compute a win rate. Two rules matter more than any code:

  1. Measure win rate by resolved markets, not by individual trades. A wallet that scalps one market a hundred times is one data point, not a hundred.
  2. Require history. A 3 for 3 wallet is noise; a meaningful sample starts around ten resolved markets.

Where DIY breaks

Everything above works, and we know because our own index started the same way. It now covers 1.5B+ fills across 3.1M wallets with at least one fill, and these are the walls we hit on the way:

Farmers poison every naive leaderboard. A wallet that buys Yes at 96 cents and settles at 1 dollar wins almost every time while predicting nothing. Among wallets with a 90 percent or higher win rate, 43,179, about 61 percent, are farmers. Their mathematical fingerprint is an average buy price at or above 95 cents. If you rank by win rate without filtering them, your entire top is farmers. The full detection logic is documented on our farmer filter page.

P&L is not in the trades feed. Winning positions are usually redeemed, not sold, and redemptions live in the /activity feed as REDEEM events, not in /trades. Skip them and every winner looks like a bagholder. Honest accounting is FIFO per wallet per market across every fill and redemption the wallet ever made.

NegRisk markets double-count. Polymarket's linked multi-outcome markets settle through split and merge flows that a naive calculation counts twice. Resolved P&L on them has to be corrected, or win rates drift upward across the board. Our correction is described in the methodology.

Hedges look like alpha. A wallet holding both sides of correlated markets shows steady profit that is spread capture, not a directional call. Copying it teaches you nothing about the outcome.

None of these are exotic edge cases. They are the bulk of what separates a weekend script from a signal you would trade on.

Or take the ready-made version

If you want the monitor without maintaining the pipeline, this is exactly what OrcaLayer is: the same public chain data, indexed from 1.5B+ on-chain fills, farmer-filtered, NegRisk-corrected, with FIFO P&L per wallet. The leaderboard ranks smart money wallets, the whale alerts feed streams every trade of 500 dollars or more live, and Sonar draws the whole capital flow as a map. For your own code there is a REST API, Python SDK and MCP server reading the same index this site runs on.

Both paths work. The difference is whether the farmer filter, the NegRisk correction and the redemption accounting are your problem or ours.

See the data live โ€” free wallet lookup

Every Polymarket trader profile, smart-money flag, lifetime P&L, farmer detection, ISW alignment โ€” searchable in one place.