Comparison July 26, 2026

How trade streaming beats the public Polymarket API for tracking wallets

Polling Polymarket's API for wallet positions lags 3–120 seconds. Streaming trades and applying them locally keeps positions current in real time.

To track how many shares a wallet holds on Polymarket you can either poll the public API — and be 3 to 120 seconds behind — or subscribe to a trade stream and update the position yourself the millisecond each trade happens. If a bot is making decisions from that number, the second approach isn’t an optimization; it’s the difference between reacting to the market and reacting to its history.

This comes up the moment you build anything serious: you need wallet state. Your own bot’s position (so it knows its exposure before adding to it), or the position of a whale you’re copy-trading (are they opening, adding, or unwinding?). Same problem either way — and two very different ways to solve it.

Way 1: poll the public API

Polymarket’s public data API will tell you any wallet’s current positions — every trade is settled on-chain, so holdings are public information. The naive tracker is a loop:

import time, requests

WALLET = "0xWhale..."

while True:
    positions = requests.get(
        "https://data-api.polymarket.com/positions",
        params={"user": WALLET},
    ).json()
    # ... react to changes ...
    time.sleep(5)

Simple, and fine for a dashboard you glance at. For a trading system it has three structural problems:

  1. It’s stale by design. The API serves processed on-chain state — activity flows through confirmation, indexing, and caching before it reaches you. In practice, position data lags real activity by ~3 to 120 seconds, sometimes more. You’re not seeing the whale’s position; you’re seeing what it was.
  2. Polling doesn’t scale. Tighten the loop and you hit rate limits. Track ten wallets and you’ve multiplied every request. There is no polling interval that is both fresh and polite.
  3. You see states, not events. If the whale bought and fully sold between two polls, you saw nothing. The diff between snapshots hides the very activity you wanted to catch.

Way 2: maintain state from the trade stream

The alternative flips the direction: instead of repeatedly asking “what’s the position now?”, derive the position yourself from the events that change it. Every trade streams to you; a buy adds shares, a sell removes them:

import asyncio, json, websockets
from collections import defaultdict

FEED = "wss://stream.polyflux.io/polymarket/<your_key>"
WATCHED = {"0xwhale...", "0xmybot..."}          # any wallets you care about

positions = defaultdict(float)                   # (wallet, outcome) -> shares

def apply(t):
    wallet = t["wallet_address"].lower()
    if wallet not in WATCHED:
        return
    key = (wallet, outcome_of(t))                # the outcome token traded —
    delta = float(t["size"])                     # print a raw event to see it
    positions[key] += delta if t["operation_type"] == "buy" else -delta
    print(f"{wallet} now holds {positions[key]:.0f} @ {key[1]}")

async def main():
    async with websockets.connect(FEED) as ws:
        async for raw in ws:
            msg = json.loads(raw)
            if msg.get("type") != "events":
                continue
            for t in msg["events"]:
                if t.get("event_type") == "trade":
                    apply(t)

asyncio.run(main())

This is event sourcing, and it changes what you know and when:

  • The position updates the moment the trade streams in — while the same trade still has confirmation processing, indexing, and caching ahead of it before any polled API will reflect it.
  • One connection covers every wallet. The stream carries all trades; tracking more wallets is adding an address to a set, not adding load.
  • You see every event, not periodic snapshots. The buy-then-sell that polling missed is two events you processed in order.

The practical pattern: snapshot + deltas

Don’t choose between them — sequence them. Fetch the wallet’s position from the API once at startup (your snapshot), then apply streamed trades from there (your deltas). This is the same pattern exchanges recommend for order book maintenance, applied to positions. Two honest details to handle:

  • Non-trade events move balances too. Redeems, splits, and merges change holdings without a trade. The feed labels these event_types, so you can process them or simply trigger a re-sync when one touches a watched wallet.
  • Re-sync occasionally. A periodic API check (minutes, not seconds) trues up drift. The stream gives you real-time truth; the API gives you a checkpoint. Used this way, its delay stops mattering.

Side by side

Polling the APITrade streaming
Freshness~3–120 s behind (sometimes more)Seconds ahead — as trades stream
What you seePeriodic snapshotsEvery event, in order
Missed activityAnything between pollsNothing
Scaling to N walletsN × requests, rate limitsSame one connection
SetupOne GET request~20 lines + a snapshot
Best forDashboards, startup snapshot, re-syncBots, copy-trading, live signals

The takeaway

The public API answers “what did this wallet hold, recently?” — and that’s genuinely enough for a portfolio page. But a bot acting on positions needs “what does it hold now” — and the only way to know now is to watch the trades as they happen and do the arithmetic yourself.

The arithmetic is the easy part — you just saw all of it. The hard part is the real-time feed, and that’s one WebSocket: start with the Python streaming guide, then grab a key and your tracker is live against every wallet on Polymarket — seconds ahead of the API you’d otherwise be polling.

Frequently asked questions

How do I get a wallet's positions on Polymarket?
Two ways: query Polymarket's public data API for the wallet's current positions, or reconstruct positions yourself by subscribing to a real-time trade stream and applying each of the wallet's trades as it happens. The API is simpler; the stream is seconds fresher.
How delayed is the Polymarket API for positions?
Position data served by the public API reflects processed on-chain state, and in practice lags real activity by roughly 3 to 120 seconds — occasionally longer under load. A real-time trade stream delivers the same activity as it happens, so a locally maintained position is always seconds fresher.
Can I track someone else's Polymarket wallet in real time?
Yes. All trading is on-chain and public. Subscribe to a trade stream, filter events for that wallet_address, and apply each buy and sell to a running position — you're then tracking their holdings live, without polling anything.
Why not just poll the Polymarket API in a loop?
Polling works but scales and ages badly: each response is already seconds stale, tight loops hit rate limits, and every wallet you track multiplies the requests. A single trade stream carries every wallet's activity in one connection with no polling at all.
What about redeems, splits, and merges — do they affect positions?
Yes — trades aren't the only events that change balances. A good feed labels these event types so you can handle them; the practical pattern is to apply trades in real time and occasionally re-sync from the API to true up anything else.
← All articles